| #include <openssl/rsa.h> | |||||
| #include <openssl/pem.h> | |||||
| #include <openssl/sha.h> | |||||
| #include <openssl/rand.h> | |||||
| #include <string.h> | |||||
| #include <assert.h> | |||||
| #include "lc6_crypto.h" | |||||
| int lc6crypto_seeded = 0; | |||||
| libchat_user* lc6crypto_genuserkey(libchat_user *user) { | |||||
| BIGNUM *bn; | |||||
| RSA *rsa; | |||||
| BIO *pub; | |||||
| BIO *priv; | |||||
| size_t publen; | |||||
| size_t privlen; | |||||
| assert(user); | |||||
| bn = BN_new(); | |||||
| BN_set_word(bn, RSA_F4); | |||||
| rsa = RSA_new(); | |||||
| RSA_generate_key_ex(rsa, 2048, bn, NULL); | |||||
| priv = BIO_new(BIO_s_mem()); | |||||
| pub = BIO_new(BIO_s_mem()); | |||||
| PEM_write_bio_RSAPrivateKey(priv, rsa, NULL, NULL, 0, NULL, NULL); | |||||
| PEM_write_bio_RSAPublicKey(pub, rsa); | |||||
| RSA_free(rsa); | |||||
| privlen = BIO_pending(priv); | |||||
| publen = BIO_pending(pub); | |||||
| user->priv_key = malloc(privlen); | |||||
| user->pub_key = malloc(publen); | |||||
| BIO_read(priv, user->priv_key, privlen); | |||||
| BIO_read(pub, user->pub_key, publen); | |||||
| user->priv_key[privlen-1] = '\0'; | |||||
| user->pub_key[publen-1] = '\0'; | |||||
| BIO_free_all(priv); | |||||
| BIO_free_all(pub); | |||||
| BN_free(bn); | |||||
| return user; | |||||
| } | |||||
| RSA * __lc6crypto_createRSA(unsigned char *key, int public) | |||||
| { | |||||
| RSA *rsa= NULL; | |||||
| BIO *keybio = NULL; | |||||
| keybio = BIO_new_mem_buf(key, -1); | |||||
| assert(keybio); | |||||
| if(public) { | |||||
| PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL); | |||||
| } | |||||
| else { | |||||
| PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL); | |||||
| } | |||||
| assert(rsa); | |||||
| return rsa; | |||||
| } | |||||
| int lc6crypto_public_encrypt( | |||||
| unsigned char *data, | |||||
| int data_len, | |||||
| unsigned char *key, | |||||
| unsigned char *enc_data) | |||||
| { | |||||
| RSA *rsa = __lc6crypto_createRSA(key,1); | |||||
| int result = RSA_public_encrypt(data_len, data, enc_data, rsa, RSA_PKCS1_OAEP_PADDING); | |||||
| return result; | |||||
| } | |||||
| int lc6crypto_private_decrypt( | |||||
| unsigned char *enc_data, | |||||
| int enc_len, | |||||
| unsigned char *key, | |||||
| unsigned char *data) | |||||
| { | |||||
| RSA *rsa = __lc6crypto_createRSA(key,0); | |||||
| int result = RSA_private_decrypt(enc_len, enc_data, data, rsa, RSA_PKCS1_OAEP_PADDING); | |||||
| return result; | |||||
| } | |||||
| int lc6crypto_private_encrypt( | |||||
| unsigned char *data, | |||||
| int data_len, | |||||
| unsigned char *key, | |||||
| unsigned char *enc_data) | |||||
| { | |||||
| RSA *rsa = __lc6crypto_createRSA(key,0); | |||||
| int result = RSA_private_encrypt(data_len, data, enc_data, rsa, RSA_PKCS1_OAEP_PADDING); | |||||
| return result; | |||||
| } | |||||
| int lc6crypto_public_decrypt( | |||||
| unsigned char *enc_data, | |||||
| int enc_len, | |||||
| unsigned char *key, | |||||
| unsigned char *data) | |||||
| { | |||||
| RSA *rsa = __lc6crypto_createRSA(key,1); | |||||
| int result = RSA_public_decrypt(enc_len, enc_data, data, rsa, RSA_PKCS1_OAEP_PADDING); | |||||
| return result; | |||||
| } | |||||
| void lc6crypto_sha256( | |||||
| unsigned char *data, | |||||
| int data_len, | |||||
| unsigned char *hash) | |||||
| { | |||||
| SHA256_CTX sha256; | |||||
| SHA256_Init(&sha256); | |||||
| SHA256_Update(&sha256, data, data_len); | |||||
| SHA256_Final(hash, &sha256); | |||||
| } | |||||
| int lc6crypto_encrypt( | |||||
| unsigned char *data, | |||||
| int data_len, | |||||
| unsigned char *encrypted, | |||||
| unsigned char *key, | |||||
| unsigned char *iv) | |||||
| { | |||||
| EVP_CIPHER_CTX *ctx; | |||||
| int encrypted_len = 0; | |||||
| int len = 0; | |||||
| if(!(ctx = EVP_CIPHER_CTX_new())) | |||||
| return -1; | |||||
| if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { | |||||
| EVP_CIPHER_CTX_free(ctx); | |||||
| return -1; | |||||
| } | |||||
| if(1 != EVP_EncryptUpdate(ctx, encrypted, &len, data, data_len)) { | |||||
| EVP_CIPHER_CTX_free(ctx); | |||||
| return -1; | |||||
| } | |||||
| encrypted_len += len; | |||||
| if(1 != EVP_EncryptFinal_ex(ctx, encrypted + len, &len)) { | |||||
| EVP_CIPHER_CTX_free(ctx); | |||||
| return -1; | |||||
| } | |||||
| encrypted_len += len; | |||||
| EVP_CIPHER_CTX_free(ctx); | |||||
| return encrypted_len; | |||||
| } | |||||
| int lc6crypto_decrypt( | |||||
| unsigned char *encrypted, | |||||
| int encrypted_len, | |||||
| unsigned char *data, | |||||
| unsigned char *key, | |||||
| unsigned char *iv) | |||||
| { | |||||
| EVP_CIPHER_CTX *ctx; | |||||
| int data_len = 0; | |||||
| int len = 0; | |||||
| if(!(ctx = EVP_CIPHER_CTX_new())) | |||||
| return -1; | |||||
| if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { | |||||
| EVP_CIPHER_CTX_free(ctx); | |||||
| return -1; | |||||
| } | |||||
| if(1 != EVP_DecryptUpdate(ctx, data, &len, encrypted, encrypted_len)) { | |||||
| EVP_CIPHER_CTX_free(ctx); | |||||
| return -1; | |||||
| } | |||||
| data_len += len; | |||||
| if(1 != EVP_DecryptFinal_ex(ctx, encrypted + len, &len)) { | |||||
| EVP_CIPHER_CTX_free(ctx); | |||||
| return -1; | |||||
| } | |||||
| data_len += len; | |||||
| EVP_CIPHER_CTX_free(ctx); | |||||
| return data_len; | |||||
| } | |||||
| int lc6crypto_random(unsigned char *data, int data_len) { | |||||
| if ( ! lc6crypto_seeded ) { | |||||
| RAND_poll(); | |||||
| lc6crypto_seeded=1; | |||||
| } | |||||
| if ( RAND_bytes(data, data_len) != 1 ) | |||||
| return -1; | |||||
| return data_len; | |||||
| } |