1. 程式人生 > >iOS基於openssl 的AES-128-cbc-pkcs5 加解密

iOS基於openssl 的AES-128-cbc-pkcs5 加解密

前段時間自己寫客戶端加密解密,查了不少資料。現在把自己寫的過程記錄下來,分享出去讓沒寫過 openssl aes 的小夥伴少鬧點心

閒話不說進入正題 

1.AES加密和DES加密的區別這裡就不提了,網上好多解釋

2.AES加密的方式有很多 128 256 cbc ecb cfb 等等,這裡介紹AES-128-cbc-pkcs5 加解密

你可以寫一個公共的加密類 也可以給系統類寫一個類的擴充套件 category

因為我的是給介面引數進行加密 所以我的就給NSString寫了一個類擴充套件,如果你自己要寫可根據自己情況寫(比如給NSData寫一個類擴充套件)

當時寫AES的時候因為好長時間不碰C了,所以開闢空間和初始化的時候經常出問題,還有就是加密解密都是單執行緒的,所以加上了執行緒鎖

解密的時候,最後不要忘了去除填充

好了不多說了直接上程式碼

4.AES-128-cbc-pkcs5 加密

-(NSString*)encryptAES:(NSString*)key
{
    @synchronized (self) {
        const char *Source;
        unsigned char *InputData=NULL;
        unsigned char *EncryptData=NULL;
        char *DecryptData=NULL;
        
        unsigned char Key[AES_BLOCK_SIZE+1];	//建議用unsigned char
        unsigned char iv[17] = "****************";	//加密的初始化向量,加密解密要一樣就行 因為CBC 是迴圈加密方式 所以這個地方的加密向量一定要和解密端商量好
        AES_KEY AesKey;
        
        int DataLen=0,SetDataLen=0;
        NSData *dat = [self dataUsingEncoding:NSUTF8StringEncoding];
        Source = [self cStringUsingEncoding:NSUTF8StringEncoding];//要加密的資料
        /**     ------------ warning warning warning warning ----------------
         *strlen()計算的是char* 的長度,但是如果輸入中間包括'\0'字元的話,
         *那麼只會加密'\0'前面啊的一段,所以這個strlen()在這個地方來計算加密解密長度 欠妥,
         *故 以'\0'來判斷字串長度,不符合,這個地方暫時以NSData 的 length 來記錄資料長度
         *      ------------ warning warning warning warning ----------------
         */
        DataLen = dat.length;
        memset(Key, 0x00, sizeof(Key));
        memcpy(Key, [key cStringUsingEncoding:NSUTF8StringEncoding], AES_BLOCK_SIZE);
        
        // set the encryption length
        SetDataLen = 0;
        if ((DataLen%AES_BLOCK_SIZE) == 0)
        {
            SetDataLen = DataLen + AES_BLOCK_SIZE;
        }
        else
        {
            SetDataLen = ((DataLen/AES_BLOCK_SIZE)+1) * AES_BLOCK_SIZE;
        }
        printf("SetDataLen:%d...\n", SetDataLen);	//取16的倍數
        
        InputData = (unsigned char *)malloc(SetDataLen + 1);
        memset(InputData, 0, SetDataLen + 1);//注意要SetDataLen+1
        if(InputData == NULL)
        {
            fprintf(stderr, "Unable to allocate memory for InputData\n");
            exit(-1);
        }
        //計算填充數字
        int nNumber;
        if (DataLen % 16 > 0)
            nNumber = SetDataLen - DataLen;
        else
            nNumber = 16;
        //填充,PKCS5填充的規則 如果加密資料餘16大於0 將餘數填充到加密資料後面湊成待加密資料長度正好是16的整數倍,如果加密資料餘16正好等於0,那麼在加密資料後面填充16個16
        memset(InputData, nNumber, SetDataLen);
        //拷貝資源
        memcpy(InputData, Source, DataLen);
        //開闢加密後的資料空間
        EncryptData = (unsigned char *)malloc(SetDataLen+1);
        if(EncryptData == NULL)	//注意要SetDataLen+1
        {
            fprintf(stderr, "Unable to allocate memory for EncryptData\n");
            exit(-1);
        }
        memset(EncryptData, 0, SetDataLen+1);
        //設定加密金鑰
        memset(&AesKey, 0x00, sizeof(AES_KEY));
        if(AES_set_encrypt_key(Key, 128, &AesKey) < 0)
        {
            fprintf(stderr, "Unable to set encryption key in AES...\n");
            exit(-1);
        }
        //加密
        AES_cbc_encrypt((unsigned char *)InputData, (unsigned char *)EncryptData,
                        SetDataLen, &AesKey, iv, AES_ENCRYPT);
        //將加密後的資料轉成NSData
        NSData *result = [NSData dataWithBytes:EncryptData length:SetDataLen];
        //釋放記憶體
        if(InputData != NULL)
        {
            free(InputData);
            InputData = NULL;
        }
        
        if(EncryptData != NULL)
        {
            free(EncryptData);
            EncryptData = NULL;
        }
        
        if(DecryptData != NULL)
        {
            free(DecryptData);
            DecryptData = NULL;
        }
        //返回base64編碼字串 使用的GTMBase64 如果你不用這個 可以替換成泥自己的Base64編碼方式
        return [GTMBase64 stringByEncodingData:result];
    }
    
    
}

5.AES128cbcpkcs5解密
-(NSString*)decryptAESData:(NSString*)key{
    @synchronized (self) {
        const char *Source;
        char *InputData=NULL;
        char *EncryptData=NULL;
        char *DecryptData=NULL;
        
        unsigned char Key[AES_BLOCK_SIZE+1];	//建議用unsigned char
        unsigned char iv[17] = <span style="font-family: Arial, Helvetica, sans-serif;">"****************"</span>;	//加密的初始化向量,加密解密要一樣就行
        AES_KEY AesKey;
        int DataLen=0,SetDataLen=0, i;
        NSData *da = [GTMBase64 decodeString:self];
        Source = [[GTMBase64 decodeString:self] bytes];//[self cStringUsingEncoding:NSUTF8StringEncoding];//要解密的資料
        DataLen = da.length;
        memset(Key, 0x00, sizeof(Key));
        memcpy(Key, [key cStringUsingEncoding:NSUTF8StringEncoding], AES_BLOCK_SIZE);
        
        // set the encryption length
        SetDataLen = 0;
        if ((DataLen%AES_BLOCK_SIZE) == 0)
        {
            SetDataLen = DataLen;
        }
        else
        {
            SetDataLen = ((DataLen/AES_BLOCK_SIZE)+1) * AES_BLOCK_SIZE;
        }
        if(AES_set_decrypt_key(Key, 128, &AesKey) < 0)
        {//設定解密金鑰
            fprintf(stderr, "Unable to set encryption key in AES...\n");
            exit(-1);
        }
        DecryptData = (char *)calloc(SetDataLen + 16, sizeof(char));
        //解密
        AES_cbc_encrypt((unsigned char *)Source, (unsigned char *)DecryptData,
                        SetDataLen, &AesKey, iv, AES_DECRYPT);
        
        NSData *result = [NSData dataWithBytes:DecryptData length:SetDataLen];
        
        if(InputData != NULL)
        {
            free(InputData);
            InputData = NULL;
        }
        
        if(EncryptData != NULL)
        {
            free(EncryptData);
            EncryptData = NULL;
        }
        
        if(DecryptData != NULL)
        {
            free(DecryptData);
            DecryptData = NULL;
        }
        NSString *backStr = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
//        NSLog(@"%@",backStr);
        //因為加密的時候進行了填充,所以在這個地方需要去除填充
        int c = (int)[backStr characterAtIndex:backStr.length - 1];
        NSString *sss = [backStr substringToIndex:backStr.length - c];
        NSLog(@"%@",sss);
        return sss;
    }
    
}
好了 差不多 AES128cbcpkcs5 加密解密都在上面了