2012-11-12 151 views
1

我试图做本地代码C.加密AES加密/解密的工作,但,当我尝试解密字符串。它不会以原始字符串结尾。这里是一个不基于模式PARAM加密/ decrpt的JNI方法:Android的JNI字符串加密/解密

jbyteArray Java_com_example_hellojni_HelloJni_encrypt(JNIEnv* env, 
             jobject this, 
             jbyteArray srcData, 
             jint mode) 
{ 
    // get length of bytes 
    int srcLen=(*env)->GetArrayLength(env,srcData); 

    //convert jbyteArray to byte [] 
    jbyte data[srcLen]; 
    (*env)->GetByteArrayRegion(env, srcData, 0, srcLen, data); 
    (*env)->ReleaseByteArrayElements(env, srcData,data , 0); 


    unsigned char* indata=(unsigned char*)data; 
    const unsigned char ukey[] = { 'H','A','R','D','C','O','D','E','D',' ','K','E','Y','1','2','3'}; 
    unsigned char *outdata = NULL; 
    outdata = malloc(srcLen); 
    AES_KEY key; 
    memset(&key, 0, sizeof(AES_KEY)); 

if(mode == AES_ENCRYPT) 
    AES_set_encrypt_key(ukey, 128, &key); 
else 
    AES_set_decrypt_key(ukey, 128, &key); 

AES_ecb_encrypt(indata, outdata, &key, mode); 

jbyteArray bArray = (*env)->NewByteArray(env, srcLen); 
jboolean isCopy; 
void *decrypteddata = (*env)->GetPrimitiveArrayCritical(env, (jarray)bArray, &isCopy); 
memcpy(decrypteddata, outdata, srcLen); 

(*env)->ReleasePrimitiveArrayCritical(env, bArray, decrypteddata, 0); 

return bArray; 
} 

任何想法,为什么对加密的字节是不是像原来一样?

至于建议的科多和owlstead我想仍然有同样的问题,更高一级的执行。

下面是从saju.net.in/code/misc/openssl_aes.c.txt代码

/** 
* Create an 256 bit key and IV using the supplied key_data. salt can be added for taste. 
* Fills in the encryption and decryption ctx objects and returns 0 on success 
**/ 
int aes_init(unsigned char *key_data, int key_data_len, unsigned char *salt, EVP_CIPHER_CTX *e_ctx, 
     EVP_CIPHER_CTX *d_ctx) 
{ 
    int i, nrounds = 5; 
    unsigned char key[32], iv[32]; 

    /* 
    * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material. 
    * nrounds is the number of times the we hash the material. More rounds are more secure but 
    * slower. 
    */ 
    i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, key_data_len, nrounds, key, iv); 
    if (i != 32) { 
    printf("Key size is %d bits - should be 256 bits\n", i); 
    return -1; 
} 

EVP_CIPHER_CTX_init(e_ctx); 
EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv); 
EVP_CIPHER_CTX_init(d_ctx); 
EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv); 

return 0; 
} 

/* 
* Encrypt *len bytes of data 
* All data going in & out is considered binary (unsigned char[]) 
*/ 
unsigned char *aes_encrypt(EVP_CIPHER_CTX *e, unsigned char *plaintext, int *len) 
{ 
    /* max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes */ 
    int c_len = *len + AES_BLOCK_SIZE, f_len = 0; 
    unsigned char *ciphertext = malloc(c_len); 

    /* allows reusing of 'e' for multiple encryption cycles */ 
    EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL); 

    /* update ciphertext, c_len is filled with the length of ciphertext generated, 
    *len is the size of plaintext in bytes */ 
    EVP_EncryptUpdate(e, ciphertext, &c_len, plaintext, *len); 

    /* update ciphertext with the final remaining bytes */ 
    EVP_EncryptFinal_ex(e, ciphertext+c_len, &f_len); 

*len = c_len + f_len; 
return ciphertext; 
} 

/* 
* Decrypt *len bytes of ciphertext 
*/ 
unsigned char *aes_decrypt(EVP_CIPHER_CTX *e, const unsigned char *ciphertext, int *len) 
{ 
    /* because we have padding ON, we must allocate an extra cipher block size of memory */ 
    int p_len = *len, f_len = 0; 
    unsigned char *plaintext = malloc(p_len + AES_BLOCK_SIZE); 

    EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL); 
    EVP_DecryptUpdate(e, plaintext, &p_len, ciphertext, *len); 
    EVP_DecryptFinal_ex(e, plaintext+p_len, &f_len); 

    *len = p_len + f_len; 
    return plaintext; 
} 

这里是我的方法是所谓格式的Java:

/* "opaque" encryption, decryption ctx structures that libcrypto uses to record 
status of enc/dec operations */ 
EVP_CIPHER_CTX en, de; 


jint 
Java_com_example_hellojni_HelloJni_aesinit(JNIEnv* env, 
               jobject obj) 
{ 
     unsigned int salt[] = {12345, 54321}; 
     unsigned char key_data[]={ 'G','X','8','j','E','r','0','4','o','6','P','C','+','I','E','+'}; 
    int key_data_len; 

    key_data_len = strlen(key_data); 

    /* gen key and iv. init the cipher ctx object */ 
    if (aes_init(key_data, key_data_len, (unsigned char *)&salt, &en, &de)) { 
    printf("Couldn't initialize AES cipher\n"); 
    __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "initializing aes failed"); 
    return 0; 
    } 
    __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "initializing aes success"); 

    return 1; 
} 


    jint 
    Java_com_example_hellojni_HelloJni_aesCleanup(JNIEnv* env, 
               jobject obj) 
    { 
EVP_CIPHER_CTX_cleanup(&en); 
EVP_CIPHER_CTX_cleanup(&de); 
return 1; 
    } 



    jbyteArray 
    Java_com_example_hellojni_HelloJni_encrypt(JNIEnv* env, 
               jobject obj, jstring textToEncrypt) 
    { 

    const char *plainText = (*env)->GetStringUTFChars(env, textToEncrypt, 0); 
    int len = strlen(plainText)+1; 
    unsigned char *ciphertext = aes_encrypt(&en, (unsigned char *)plainText, &len); 

     jbyteArray byteArray=(*env)->NewByteArray(env, strlen(ciphertext)); 
    (*env)->SetByteArrayRegion(env, byteArray, 0, strlen(ciphertext), (const jbyte*)ciphertext); 

    (*env)->ReleaseStringUTFChars(env, textToEncrypt, plainText); 


    return byteArray; 

    } 



    jbyteArray 
    Java_com_example_hellojni_HelloJni_decrypt(JNIEnv* env, 
               jobject obj, jstring textToDecrypt) 
    { 


    const unsigned char *cipherText = (*env)->GetStringUTFChars(env, textToDecrypt, NULL); 
    int len = strlen(cipherText)+1; 
    char *plainText = (char *)aes_decrypt(&de, cipherText, &len); 
    jbyteArray byteArray=(*env)->NewByteArray(env, strlen(plainText)); 
    (*env)->SetByteArrayRegion(env, byteArray, 0, strlen(plainText), (const jbyte*)plainText); 

    (*env)->ReleaseStringUTFChars(env, textToDecrypt, cipherText); 


    return byteArray; 

} 
+0

有你找到一个解决方案吗?如果是的话可以请您与我分享我有同样的问题 –

回答

0

您提供一个长72位的密钥(9个字符×8位)。但是它需要128位长(正如您在拨打AES_set_encrypt_key时指定的那样)。因此,缺失的56位将或多或少是随机的(取决于ukey阵列旁边的内容)。

为了修正它,指定一个较长的键或用0填充其余字节。

+0

我改变了密钥为16个字符长,但还是同样的结果。更新了上面的代码 – Saqib

+0

您的数据是16字节的倍数吗? – Codo

+0

没有它没有。数据可以是任何长度的,这取决于在什么字符串用户类型。我使用的getBytes() – Saqib

0

您正在使用OpenSSL的低级别的加密模式。如果您使用更高级别的方法(如EVP_*),您的麻烦可能会消失。用于AES/CBC模式加密。另请参阅this related question

+0

正如您所建议的,我使用了此实现saju.net.in/代码/ misc/openssl_aes.c.txt,但仍然找不到正确的方法。请参阅上面的编辑 – Saqib