static int w_crypto_aes_decrypt(sip_msg_t* msg, char* inb, char* keyb, char* outb) { str ins; str keys; pv_spec_t *dst; pv_value_t val; EVP_CIPHER_CTX *de=NULL; str etext; if (fixup_get_svalue(msg, (gparam_t*)inb, &ins) != 0) { LM_ERR("cannot get input value\n"); return -1; } if (fixup_get_svalue(msg, (gparam_t*)keyb, &keys) != 0) { LM_ERR("cannot get key value\n"); return -1; } de = EVP_CIPHER_CTX_new(); if(de==NULL) { LM_ERR("cannot get new cipher context\n"); return -1; } dst = (pv_spec_t*)outb; /* gen key and iv. init the cipher ctx object */ if (crypto_aes_init((unsigned char *)keys.s, keys.len, (unsigned char*)((_crypto_salt_param)?_crypto_salt:0), NULL, de)) { EVP_CIPHER_CTX_free(de); LM_ERR("couldn't initialize AES cipher\n"); return -1; } memset(&val, 0, sizeof(pv_value_t)); etext.s = pv_get_buffer(); etext.len = base64_dec((unsigned char *)ins.s, ins.len, (unsigned char *)etext.s, pv_get_buffer_size()-1); if (etext.len < 0) { EVP_CIPHER_CTX_free(de); LM_ERR("base64 inpuy with encrypted value is too large (need %d)\n", -etext.len); return -1; } val.rs.len = etext.len; val.rs.s = (char *)crypto_aes_decrypt(de, (unsigned char *)etext.s, &val.rs.len); if(val.rs.s==NULL) { EVP_CIPHER_CTX_free(de); LM_ERR("AES decryption failed\n"); return -1; } LM_DBG("plain result: [%.*s]\n", val.rs.len, val.rs.s); val.flags = PV_VAL_STR; dst->setf(msg, &dst->pvp, (int)EQ_T, &val); free(val.rs.s); EVP_CIPHER_CTX_cleanup(de); EVP_CIPHER_CTX_free(de); return 1; }
/** * testing function */ int crypto_aes_test(void) { /* "opaque" encryption, decryption ctx structures * that libcrypto uses to record status of enc/dec operations */ EVP_CIPHER_CTX en, de; /* The salt paramter is used as a salt in the derivation: * it should point to an 8 byte buffer or NULL if no salt is used. */ unsigned char salt[] = {1,2,3,4,5,6,7,8}; unsigned char *key_data; int key_data_len, i; char *input[] = {"Kamailio - The Open Source SIP Server", "Thank you for flying Kamailio!", "100 Trying\nYour call is important to us", NULL }; /* the key_data for testing */ key_data = (unsigned char *)"kamailio-sip-server"; key_data_len = strlen((const char *)key_data); /* gen key and iv. init the cipher ctx object */ if (crypto_aes_init(key_data, key_data_len, salt, &en, &de)) { LM_ERR("couldn't initialize AES cipher\n"); return -1; } /* encrypt and decrypt each input string and compare with the original */ for (i = 0; input[i]; i++) { char *plaintext; unsigned char *ciphertext; int olen, len; /* The enc/dec functions deal with binary data and not C strings. * strlen() will return length of the string without counting the '\0' * string marker. We always pass in the marker byte to the * encrypt/decrypt functions so that after decryption we end up with * a legal C string */ olen = len = strlen(input[i])+1; ciphertext = crypto_aes_encrypt(&en, (unsigned char *)input[i], &len); plaintext = (char *)crypto_aes_decrypt(&de, ciphertext, &len); if (strncmp(plaintext, input[i], olen)) LM_ERR("FAIL: enc/dec failed for \"%s\"\n", input[i]); else LM_NOTICE("OK: enc/dec ok for \"%s\"\n", plaintext); free(ciphertext); free(plaintext); } EVP_CIPHER_CTX_cleanup(&de); EVP_CIPHER_CTX_cleanup(&en); return 0; }
static int w_crypto_aes_encrypt(sip_msg_t* msg, char* inb, char* keyb, char* outb) { str ins; str keys; pv_spec_t *dst; pv_value_t val; EVP_CIPHER_CTX en; str etext; if (fixup_get_svalue(msg, (gparam_t*)inb, &ins) != 0) { LM_ERR("cannot get input value\n"); return -1; } if (fixup_get_svalue(msg, (gparam_t*)keyb, &keys) != 0) { LM_ERR("cannot get key value\n"); return -1; } dst = (pv_spec_t*)outb; /* gen key and iv. init the cipher ctx object */ if (crypto_aes_init((unsigned char *)keys.s, keys.len, (unsigned char*)((_crypto_salt_param)?_crypto_salt:0), &en, NULL)) { LM_ERR("couldn't initialize AES cipher\n"); return -1; } etext.len = ins.len; etext.s = (char *)crypto_aes_encrypt(&en, (unsigned char *)ins.s, &etext.len); if(etext.s==NULL) { LM_ERR("AES encryption failed\n"); return -1; } memset(&val, 0, sizeof(pv_value_t)); val.rs.s = pv_get_buffer(); val.rs.len = base64_enc((unsigned char *)etext.s, etext.len, (unsigned char *)val.rs.s, pv_get_buffer_size()-1); if (val.rs.len < 0) { LM_ERR("base64 output of encrypted value is too large (need %d)\n", -val.rs.len); goto error; } LM_DBG("base64 encrypted result: [%.*s]\n", val.rs.len, val.rs.s); val.flags = PV_VAL_STR; dst->setf(msg, &dst->pvp, (int)EQ_T, &val); free(etext.s); EVP_CIPHER_CTX_cleanup(&en); return 1; error: free(etext.s); EVP_CIPHER_CTX_cleanup(&en); return -1; }
/***************************************************************************** * 函 数 名 : crypto_encrypt * * 功能描述 : 使用指定的密钥和指定的算法对输入的数据加密,输出加密后的数据。 * 当前支持AES-ECB算法。 * * 输入参数 : data: 待加密数据。 * len: 待加密数据长度。(byte) * algorithm: 所用HASH算法。 * key: 密钥buffer。 * klen: 密钥buffer长度。(byte) * cipher_len: 加密后的数据的存放buffer的buffer size。(byte)(没有检查) * * 输出参数 : cipher_data: 加密后的数据的存放buffer。 * cipher_len: 加密后的数据的实际长度。(byte) * * 返 回 值 : BSP_OK: 加密成功。 * BSP_ERROR: 加密失败。 * * 其它说明 : cipher_len为输入/输出参数,传入的cipher_len变量所用内存必须可写回。 * 所以避免直接传入类似sizeof()的函数调用结果。 * *****************************************************************************/ int crypto_encrypt_o (char *data, int len, CRYPTO_ENCRYPT_ALGORITHM algorithm, char *key, int klen, char *cipher_data, int *cipher_len) { crypto_aes aes_ctx; int16 keybits = 0; if(data == NULL || key == NULL || cipher_data == NULL || cipher_len == NULL) { security_print("ERROR crypto_encrypt: param is NULL pointer!\n"); return BSP_ERROR; } if(len<=0 || (klen != AES_KEY_LEN && klen != 16)) { security_print("ERROR crypto_encrypt: param is invalid!\n"); return BSP_ERROR; } if (klen == 16) { keybits = 128;/* [false alarm]:误报 */ } else if(klen == AES_KEY_LEN) { keybits = 256;/* [false alarm]:误报 */ } crypto_aes_init(&aes_ctx,(UINT8*)key,keybits,MODE_ECB,NULL); switch(algorithm) { case CRYPTO_ENCRYPT_ALGORITHM_AES_ECB: //if(0 != crypto_aes_encrypt_pad(&aes_ctx,data,len,cipher_data,cipher_len)) if(0 != crypto_aes_encrypt_block(&aes_ctx,(UINT8*)data,len,(UINT8*)cipher_data,(int32*)cipher_len)) { security_print("ERROR crypto_encrypt: crypto_aes_encrypt_pad failed!\n"); return BSP_ERROR; } break; default: security_print("ERROR crypto_encrypt: unknown algorithm!\n"); return BSP_ERROR; } return BSP_OK; }
/***************************************************************************** * 函 数 名 : crypto_decrypt * * 功能描述 : 使用指定的密钥和指定的算法对输入的数据解密,输出解密后的数据。 * 当前支持AES-ECB算法。 * * 输入参数 : * cipher_data: 待密的数据的存放buffer。 * cipher_len: 待解密的数据的实际长度。(byte) * algorithm: 所用解密算法,暂只提供AES-ECB。 * key: 密钥buffer。 * klen: 密钥buffer长度。(byte) * len: 解密后的数据的存放buffer的buffer size。(byte)(没有检查) * * 输出参数 : * data: 解密后的数据。 * len: 解密后的数据长度。(byte) * * 返 回 值 : BSP_OK: 解密成功。 * BSP_ERROR: 解密失败。 * * 其它说明 : len为输入/输出参数,传入的len变量所用内存必须可写回。 * 所以避免直接传入类似sizeof()的函数调用结果。 * *****************************************************************************/ int crypto_decrypt_o (char *cipher_data,int cipher_len,CRYPTO_ENCRYPT_ALGORITHM algorithm, char *key, int klen, char *data, int *len) { crypto_aes aes_ctx; if((cipher_data == NULL) || (cipher_len == 0) || (data == NULL) || (key == NULL)) { security_print("ERROR crypto_decrypt: param is NULL pointer!\n"); return BSP_ERROR; } if(cipher_len<=0 || klen != AES_KEY_LEN) { security_print("ERROR crypto_decrypt: param is invalid!\n"); return BSP_ERROR; } crypto_aes_init(&aes_ctx,(UINT8*)key,256,MODE_ECB,NULL); switch(algorithm) { case CRYPTO_ENCRYPT_ALGORITHM_AES_ECB: if(0 != crypto_aes_decrypt_block(&aes_ctx, (uint8 *)cipher_data, (int32)cipher_len, (uint8 *)data, (int32 *)len )) { security_print("ERROR crypto_decrypt: crypto_aes_decrypt_block failed!\n"); return BSP_ERROR; } break; default: security_print("ERROR crypto_decrypt: unknown algorithm!\n"); return BSP_ERROR; } return BSP_OK; }