iOS基於openssl 的AES-128-cbc-pkcs5 加解密
阿新 • • 發佈:2019-02-16
前段時間自己寫客戶端加密解密,查了不少資料。現在把自己寫的過程記錄下來,分享出去讓沒寫過 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.AES-128-cbc-pkcs5解密
好了 差不多 AES-128-cbc-pkcs5 加密解密都在上面了-(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; } }