aboutsummaryrefslogtreecommitdiff
path: root/src/libcrypto.c
diff options
context:
space:
mode:
authorMichael Wilder <wilder.michael@cimcor.com>2015-08-21 13:43:25 -0500
committerAndreas Schneider <asn@cryptomilk.org>2015-09-07 07:45:01 +0200
commite6f93c887ba5e62d6c5b5f87ec1910fb25f6bbad (patch)
treeba6ac48c65b6510c827b2be79d1256cc2b4608ed /src/libcrypto.c
parent36d9b62f1fa5493a54a1e776422b032f66bc0936 (diff)
downloadlibssh-e6f93c887ba5e62d6c5b5f87ec1910fb25f6bbad.tar.gz
libssh-e6f93c887ba5e62d6c5b5f87ec1910fb25f6bbad.tar.xz
libssh-e6f93c887ba5e62d6c5b5f87ec1910fb25f6bbad.zip
crypto: Add OpenSSL EVP functions for FIPS compatibility
Signed-off-by: Michael Wilder <wilder.michael@cimcor.com>
Diffstat (limited to 'src/libcrypto.c')
-rw-r--r--src/libcrypto.c552
1 files changed, 409 insertions, 143 deletions
diff --git a/src/libcrypto.c b/src/libcrypto.c
index 00f107f7..1aa54b6c 100644
--- a/src/libcrypto.c
+++ b/src/libcrypto.c
@@ -90,27 +90,42 @@ void ssh_reseed(void){
#endif
}
-SHACTX sha1_init(void) {
- SHACTX c = malloc(sizeof(*c));
- if (c == NULL) {
- return NULL;
- }
- SHA1_Init(c);
-
- return c;
+SHACTX sha1_init(void)
+{
+ int rc;
+ SHACTX c = EVP_MD_CTX_create();
+ if (c == NULL) {
+ return NULL;
+ }
+ EVP_MD_CTX_init(c);
+ rc = EVP_DigestInit_ex(c, EVP_sha1(), NULL);
+ if (rc == 0) {
+ EVP_MD_CTX_destroy(c);
+ c = NULL;
+ }
+ return c;
}
-void sha1_update(SHACTX c, const void *data, unsigned long len) {
- SHA1_Update(c,data,len);
+void sha1_update(SHACTX c, const void *data, unsigned long len)
+{
+ EVP_DigestUpdate(c, data, len);
}
-void sha1_final(unsigned char *md, SHACTX c) {
- SHA1_Final(md, c);
- SAFE_FREE(c);
+void sha1_final(unsigned char *md, SHACTX c)
+{
+ unsigned int mdlen = 0;
+
+ EVP_DigestFinal(c, md, &mdlen);
+ EVP_MD_CTX_destroy(c);
}
-void sha1(unsigned char *digest, int len, unsigned char *hash) {
- SHA1(digest, len, hash);
+void sha1(unsigned char *digest, int len, unsigned char *hash)
+{
+ SHACTX c = sha1_init();
+ if (c != NULL) {
+ sha1_update(c, digest, len);
+ sha1_final(hash, c);
+ }
}
#ifdef HAVE_OPENSSL_ECC
@@ -165,93 +180,147 @@ void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
}
#endif
-SHA256CTX sha256_init(void){
- SHA256CTX c = malloc(sizeof(*c));
- if (c == NULL) {
- return NULL;
- }
- SHA256_Init(c);
-
- return c;
-}
-
-void sha256_update(SHA256CTX c, const void *data, unsigned long len){
- SHA256_Update(c,data,len);
-}
-
-void sha256_final(unsigned char *md, SHA256CTX c) {
- SHA256_Final(md, c);
- SAFE_FREE(c);
+SHA256CTX sha256_init(void)
+{
+ int rc;
+ SHA256CTX c = EVP_MD_CTX_create();
+ if (c == NULL) {
+ return NULL;
+ }
+ EVP_MD_CTX_init(c);
+ rc = EVP_DigestInit_ex(c, EVP_sha256(), NULL);
+ if (rc == 0) {
+ EVP_MD_CTX_destroy(c);
+ c = NULL;
+ }
+ return c;
}
-void sha256(unsigned char *digest, int len, unsigned char *hash) {
- SHA256(digest, len, hash);
+void sha256_update(SHA256CTX c, const void *data, unsigned long len)
+{
+ EVP_DigestUpdate(c, data, len);
}
-SHA384CTX sha384_init(void){
- SHA384CTX c = malloc(sizeof(*c));
- if (c == NULL) {
- return NULL;
- }
- SHA384_Init(c);
+void sha256_final(unsigned char *md, SHA256CTX c)
+{
+ unsigned int mdlen = 0;
- return c;
+ EVP_DigestFinal(c, md, &mdlen);
+ EVP_MD_CTX_destroy(c);
}
-void sha384_update(SHA384CTX c, const void *data, unsigned long len){
- SHA384_Update(c,data,len);
+void sha256(unsigned char *digest, int len, unsigned char *hash)
+{
+ SHA256CTX c = sha256_init();
+ if (c != NULL) {
+ sha256_update(c, digest, len);
+ sha256_final(hash, c);
+ }
}
-void sha384_final(unsigned char *md, SHA384CTX c) {
- SHA384_Final(md, c);
- SAFE_FREE(c);
+SHA384CTX sha384_init(void)
+{
+ int rc;
+ SHA384CTX c = EVP_MD_CTX_create();
+ if (c == NULL) {
+ return NULL;
+ }
+ EVP_MD_CTX_init(c);
+ rc = EVP_DigestInit_ex(c, EVP_sha384(), NULL);
+ if (rc == 0) {
+ EVP_MD_CTX_destroy(c);
+ c = NULL;
+ }
+ return c;
}
-void sha384(unsigned char *digest, int len, unsigned char *hash) {
- SHA384(digest, len, hash);
+void sha384_update(SHA384CTX c, const void *data, unsigned long len)
+{
+ EVP_DigestUpdate(c, data, len);
}
-SHA512CTX sha512_init(void){
- SHA512CTX c = malloc(sizeof(*c));
- if (c == NULL) {
- return NULL;
- }
- SHA512_Init(c);
+void sha384_final(unsigned char *md, SHA384CTX c)
+{
+ unsigned int mdlen = 0;
- return c;
+ EVP_DigestFinal(c, md, &mdlen);
+ EVP_MD_CTX_destroy(c);
}
-void sha512_update(SHA512CTX c, const void *data, unsigned long len){
- SHA512_Update(c,data,len);
+void sha384(unsigned char *digest, int len, unsigned char *hash)
+{
+ SHA384CTX c = sha384_init();
+ if (c != NULL) {
+ sha384_update(c, digest, len);
+ sha384_final(hash, c);
+ }
}
-void sha512_final(unsigned char *md, SHA512CTX c) {
- SHA512_Final(md, c);
- SAFE_FREE(c);
+SHA512CTX sha512_init(void)
+{
+ int rc = 0;
+ SHA512CTX c = EVP_MD_CTX_create();
+ if (c == NULL) {
+ return NULL;
+ }
+ EVP_MD_CTX_init(c);
+ rc = EVP_DigestInit_ex(c, EVP_sha512(), NULL);
+ if (rc == 0) {
+ EVP_MD_CTX_destroy(c);
+ c = NULL;
+ }
+ return c;
}
-void sha512(unsigned char *digest, int len, unsigned char *hash) {
- SHA512(digest, len, hash);
+void sha512_update(SHA512CTX c, const void *data, unsigned long len)
+{
+ EVP_DigestUpdate(c, data, len);
}
-MD5CTX md5_init(void) {
- MD5CTX c = malloc(sizeof(*c));
- if (c == NULL) {
- return NULL;
- }
+void sha512_final(unsigned char *md, SHA512CTX c)
+{
+ unsigned int mdlen = 0;
- MD5_Init(c);
+ EVP_DigestFinal(c, md, &mdlen);
+ EVP_MD_CTX_destroy(c);
+}
- return c;
+void sha512(unsigned char *digest, int len, unsigned char *hash)
+{
+ SHA512CTX c = sha512_init();
+ if (c != NULL) {
+ sha512_update(c, digest, len);
+ sha512_final(hash, c);
+ }
}
-void md5_update(MD5CTX c, const void *data, unsigned long len) {
- MD5_Update(c, data, len);
+MD5CTX md5_init(void)
+{
+ int rc;
+ MD5CTX c = EVP_MD_CTX_create();
+ if (c == NULL) {
+ return NULL;
+ }
+ EVP_MD_CTX_init(c);
+ rc = EVP_DigestInit_ex(c, EVP_md5(), NULL);
+ if(rc == 0) {
+ EVP_MD_CTX_destroy(c);
+ c = NULL;
+ }
+ return c;
}
-void md5_final(unsigned char *md, MD5CTX c) {
- MD5_Final(md,c);
- SAFE_FREE(c);
+void md5_update(MD5CTX c, const void *data, unsigned long len)
+{
+ EVP_DigestUpdate(c, data, len);
+}
+
+void md5_final(unsigned char *md, MD5CTX c)
+{
+ unsigned int mdlen = 0;
+
+ EVP_DigestFinal(c, md, &mdlen);
+ EVP_MD_CTX_destroy(c);
}
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type){
@@ -371,9 +440,114 @@ void hmac_final(HMACCTX ctx, unsigned char *hashmacbuf, unsigned int *len) {
SAFE_FREE(ctx);
}
+
+/* EVP wrapper function for encrypt/decrypt */
+static void EVP_encrypt(struct ssh_cipher_struct *cipher,
+ void *in,
+ void *out,
+ unsigned long len,
+ const EVP_CIPHER* evpCipher)
+{
+ int datalen = 0;
+ int outlen = 0;
+ int outlenfinal = 0;
+ int ctxIvLen = 0;
+ int rc = 0;
+
+ EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX_init(&ctx);
+
+ rc = EVP_EncryptInit_ex(&ctx, evpCipher, NULL, (unsigned char*)cipher->key, cipher->IV);
+ if (rc == 1) {
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ rc = EVP_EncryptUpdate(&ctx, (unsigned char *)out, &outlen, (unsigned char *)in, len);
+ if(rc == 1) {
+ datalen += outlen;
+
+ rc = EVP_EncryptFinal_ex(&ctx, (unsigned char *)out + outlen, &outlenfinal);
+ if(rc == 1) {
+ datalen += outlenfinal;
+
+ /* Get size of source buffer from ctx object */
+ ctxIvLen = EVP_CIPHER_CTX_iv_length(&ctx);
+
+ /*
+ * Copy updated IV from ctx to ssh struct
+ * There is no access to the post encrypt/decrypt updated iv
+ * from openssl via an API so I'm just accessing it directly.
+ */
+ memcpy(cipher->IV, ctx.iv, ctxIvLen);
+ } else {
+ printf("EVP_EncryptFinal_ex failed\n");
+ }
+ } else {
+ printf("EVP_EncryptUpdate failed\n");
+ }
+ } else {
+ printf("EVP_EncryptInit_ex failed\n");
+ }
+ /* Cleanup */
+ EVP_CIPHER_CTX_cleanup(&ctx);
+}
+
+static void EVP_decrypt(struct ssh_cipher_struct *cipher,
+ void *in,
+ void *out,
+ unsigned long len,
+ const EVP_CIPHER* evpCipher)
+{
+ int datalen = 0;
+ int outlen = 0;
+ int outlenfinal = 0;
+ int ctxIvLen = 0;
+ int rc = 0;
+
+ EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX_init(&ctx);
+
+ rc = EVP_DecryptInit_ex(&ctx, evpCipher, NULL, (unsigned char*)cipher->key, cipher->IV);
+ if (rc == 1) {
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ rc = EVP_DecryptUpdate(&ctx, (unsigned char *)out, &outlen, (unsigned char *)in, len);
+ if (rc == 1) {
+ datalen += outlen;
+
+ rc = EVP_DecryptFinal_ex(&ctx, (unsigned char *)out + outlen, &outlenfinal);
+ if (rc == 1) {
+ datalen += outlenfinal;
+
+ /* Get size of source buffer from ctx object */
+ ctxIvLen = EVP_CIPHER_CTX_iv_length(&ctx);
+
+ /*
+ * Copy updated IV from ctx to ssh struct
+ * There is no access to the post encrypt/decrypt updated iv
+ * from openssl via an API so I'm just accessing it directly.
+ */
+ memcpy(cipher->IV, ctx.iv, ctxIvLen);
+ } else {
+ printf("EVP_DecryptFinal_ex failed\n");
+ }
+ } else {
+ printf("EVP_DecryptUpdate failed\n");
+ }
+ } else {
+ printf("EVP_DecryptInit_ex failed\n");
+ }
+
+ /* Cleanup */
+ EVP_CIPHER_CTX_cleanup(&ctx);
+}
+
+//EVP wrapper function for encrypt/decrypt
#ifdef HAS_BLOWFISH
/* the wrapper functions for blowfish */
-static int blowfish_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV){
+static int blowfish_set_key(struct ssh_cipher_struct *cipher,
+ void *key,
+ void *IV)
+{
if (cipher->key == NULL) {
if (alloc_key(cipher) < 0) {
return -1;
@@ -396,43 +570,113 @@ static void blowfish_decrypt(struct ssh_cipher_struct *cipher, void *in,
#endif /* HAS_BLOWFISH */
#ifdef HAS_AES
-static int aes_set_encrypt_key(struct ssh_cipher_struct *cipher, void *key,
- void *IV) {
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
- if (AES_set_encrypt_key(key,cipher->keysize,cipher->key) < 0) {
- SAFE_FREE(cipher->key);
- return -1;
+static int aes_set_encrypt_key(struct ssh_cipher_struct *cipher,
+ void *key,
+ void *IV)
+{
+ size_t size = 0;
+ if (cipher->key == NULL) {
+ int rc;
+
+ rc = alloc_key(cipher);
+ if (rc < 0) {
+ return -1;
+ }
+ /* cipher->keylen is the size of the cipher->key buffer so clear it
+ * Don't read or write invalid memory
+ * For the EVP functions, save the raw key which gets transformed
+ * in the EVP_EncryptInit(...)
+ */
+ memset(cipher->key, 0, cipher->keylen);
+ size = cipher->keylen;
+
+ /*
+ * Check if source buffer is smaller than destination buffer (hard coded
+ * as 32 in kex1.c - encryptkey, decryptkey, encryptIV, decryptIV)
+ * This should probably be a define, or a member of
+ * struct ssh_crypto_struct and passed as a parameter.
+ */
+ if (size > 32) {
+ size = 32;
+ }
+ memcpy(cipher->key, key, size);
}
- }
- cipher->IV=IV;
- return 0;
+ cipher->IV = IV;
+ return 0;
}
-static int aes_set_decrypt_key(struct ssh_cipher_struct *cipher, void *key,
- void *IV) {
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
- if (AES_set_decrypt_key(key,cipher->keysize,cipher->key) < 0) {
- SAFE_FREE(cipher->key);
- return -1;
+
+static int aes_set_decrypt_key(struct ssh_cipher_struct *cipher,
+ void *key,
+ void *IV)
+{
+ size_t size = 0;
+
+ if (cipher->key == NULL) {
+ int rc;
+
+ rc = alloc_key(cipher);
+ if (rc < 0) {
+ return -1;
+ }
+ /*
+ * cipher->keylen is the size of the cipher->key buffer so clear it
+ * keyLen param is the size of the void* key param
+ * Don't read or write invalid memory
+ * For the EVP functions, save the raw key which gets transformed
+ * in the EVP_EncryptInit(...)
+ */
+ memset(cipher->key, 0, cipher->keylen);
+ size = cipher->keylen;
+
+ /*
+ * Check if source buffer is smaller than destination buffer (hard coded
+ * as 32 in kex1.c - encryptkey, decryptkey, encryptIV, decryptIV)
+ * This should probably be a define, or a member of
+ * struct ssh_crypto_struct and passed as a parameter.
+ */
+ if (size > 32) {
+ size = 32;
+ }
+ memcpy(cipher->key, key, size);
}
- }
- cipher->IV=IV;
- return 0;
+ cipher->IV = IV;
+ return 0;
}
-static void aes_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
- unsigned long len) {
- AES_cbc_encrypt(in, out, len, cipher->key, cipher->IV, AES_ENCRYPT);
+static void aes_encrypt(struct ssh_cipher_struct *cipher,
+ void *in,
+ void *out,
+ unsigned long len)
+{
+ const EVP_CIPHER *pCipherType = NULL;
+
+ if (cipher->keysize == 128) {
+ pCipherType = EVP_aes_128_cbc();
+ } else if(cipher->keysize == 192) {
+ pCipherType = EVP_aes_192_cbc();
+ } else if(cipher->keysize == 256) {
+ pCipherType = EVP_aes_256_cbc();
+ }
+
+ EVP_encrypt(cipher, in, out, len, pCipherType);
}
-static void aes_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
- unsigned long len) {
- AES_cbc_encrypt(in, out, len, cipher->key, cipher->IV, AES_DECRYPT);
+static void aes_decrypt(struct ssh_cipher_struct *cipher,
+ void *in,
+ void *out,
+ unsigned long len)
+{
+ const EVP_CIPHER *pCipherType = NULL;
+
+ if (cipher->keysize == 128) {
+ pCipherType = EVP_aes_128_cbc();
+ } else if(cipher->keysize == 192) {
+ pCipherType = EVP_aes_192_cbc();
+ } else if(cipher->keysize == 256) {
+ pCipherType = EVP_aes_256_cbc();
+ }
+
+ EVP_decrypt(cipher, in, out, len, pCipherType);
}
#ifndef BROKEN_AES_CTR
@@ -445,53 +689,74 @@ static void aes_decrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
* the size of the CTR counter and incidentally the blocksize, but not the keysize.
* @param len[in] must be a multiple of AES128 block size.
*/
-static void aes_ctr128_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out,
- unsigned long len) {
- unsigned char tmp_buffer[128/8];
- unsigned int num=0;
- /* Some things are special with ctr128 :
- * In this case, tmp_buffer is not being used, because it is used to store temporary data
- * when an encryption is made on lengths that are not multiple of blocksize.
- * Same for num, which is being used to store the current offset in blocksize in CTR
- * function.
- */
- AES_ctr128_encrypt(in, out, len, cipher->key, cipher->IV, tmp_buffer, &num);
+static void aes_ctr128_encrypt(struct ssh_cipher_struct *cipher,
+ void *in,
+ void *out,
+ unsigned long len)
+{
+ if (cipher->keysize == 128) {
+ EVP_encrypt(cipher, in, out, len, EVP_aes_128_ctr());
+ } else if(cipher->keysize == 192) {
+ EVP_encrypt(cipher, in, out, len, EVP_aes_192_ctr());
+ } else if(cipher->keysize == 256) {
+ EVP_encrypt(cipher, in, out, len, EVP_aes_256_ctr());
+ }
}
#endif /* BROKEN_AES_CTR */
#endif /* HAS_AES */
#ifdef HAS_DES
-static int des3_set_key(struct ssh_cipher_struct *cipher, void *key,void *IV) {
- if (cipher->key == NULL) {
- if (alloc_key(cipher) < 0) {
- return -1;
- }
+static int des3_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV)
+{
+ size_t size = 0;
- DES_set_odd_parity(key);
- DES_set_odd_parity((void*)((uint8_t*)key + 8));
- DES_set_odd_parity((void*)((uint8_t*)key + 16));
- DES_set_key_unchecked(key, cipher->key);
- DES_set_key_unchecked((void*)((uint8_t*)key + 8), (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)));
- DES_set_key_unchecked((void*)((uint8_t*)key + 16), (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)));
- }
- cipher->IV=IV;
- return 0;
+ if (cipher->key == NULL) {
+ int rc;
+
+ rc = alloc_key(cipher);
+ if (rc < 0) {
+ return -1;
+ }
+
+ /*
+ * cipher->keylen is the size of the cipher->key buffer so clear it
+ * keyLen param is the size of the void* key param
+ * Don't read or write invalid memory
+ * For the EVP functions, save the raw key which gets transformed
+ * in the EVP_EncryptInit(...)
+ */
+ memset(cipher->key, 0, cipher->keylen);
+ size = cipher->keylen;
+
+ /*
+ * Check if source buffer is smaller than destination buffer (hard coded
+ * as 32 in kex1.c - encryptkey, decryptkey, encryptIV, decryptIV)
+ * This should probably be a define, or a member of
+ * struct ssh_crypto_struct and passed as a parameter.
+ */
+ if (size > 32) {
+ size = 32;
+ }
+ memcpy(cipher->key, key, size);
+ }
+ cipher->IV = IV;
+ return 0;
}
-static void des3_encrypt(struct ssh_cipher_struct *cipher, void *in,
- void *out, unsigned long len) {
- DES_ede3_cbc_encrypt(in, out, len, cipher->key,
- (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)),
- (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)),
- cipher->IV, 1);
+static void des3_encrypt(struct ssh_cipher_struct *cipher,
+ void *in,
+ void *out,
+ unsigned long len)
+{
+ EVP_encrypt(cipher, in, out, len, EVP_des_ede3_cbc());
}
-static void des3_decrypt(struct ssh_cipher_struct *cipher, void *in,
- void *out, unsigned long len) {
- DES_ede3_cbc_encrypt(in, out, len, cipher->key,
- (void*)((uint8_t*)cipher->key + sizeof(DES_key_schedule)),
- (void*)((uint8_t*)cipher->key + 2 * sizeof(DES_key_schedule)),
- cipher->IV, 0);
+static void des3_decrypt(struct ssh_cipher_struct *cipher,
+ void *in,
+ void *out,
+ unsigned long len)
+{
+ EVP_decrypt(cipher, in, out, len, EVP_des_ede3_cbc());
}
static void des3_1_encrypt(struct ssh_cipher_struct *cipher, void *in,
@@ -526,7 +791,8 @@ static void des3_1_decrypt(struct ssh_cipher_struct *cipher, void *in,
#endif
}
-static int des1_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV){
+static int des1_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV)
+{
if(!cipher->key){
if (alloc_key(cipher) < 0) {
return -1;