本篇文章記錄了iOS中對字串進行AES加密+Base64編碼的過程,考慮到加密物件和使用場景,理所當然的將加密過程丟到了NSString的類別中,即下面說到的NSString+AES
。
一、對AES認識有以下幾點(針對開發中涉及到的,其他的也沒有深入研究了):使用上總結起來就是——“保持一致”
特別要注意的:如果你想使用金鑰偏移量IV 那你的加密模式必須為CBC,不能使用別的模式了,具體關於加密引數,文章最後附上構造方法的引數文件。
- AES有多種加密模式:
ECB
CBC
CFB
OFB
至於用哪個看你心情了,但是要同WebService同學保持一致; - 加密解密過程需要你提供一個Key,一定是和WebService同學約定好的,不然是解密不了的;
- 偏移量(IV):非必須的,不過如果想加的話規則同上:“保持一致”;
- 補碼方式:
PKCS7Padding
PKCS5Padding
對AES的認識可以通過類似 www.seacha.com/tools/aes.h… 的線上加密網站,從UI上簡單看看構成。
二、在學習使用的時候看到網上一般有兩種Base64編碼方式:
NSData_Base-64 Encoding
:NSData類中自帶的編碼方法;GTMBase64
:我記得是Google的,具體的我也記不住了【這裡吐下槽:搜了一下GTMBase64這個關鍵詞,所有人都說“這個是啥就不說了,大家都說爛了!@#$%^&*諸如此類的話”,到頭來也沒找到一個正經的 666】
Demo中兩種編碼方式都給大家寫了,根據個人喜好選擇。GTMBase64庫可以用CocoaPods匯入。
下面是程式碼:
建立NSString的AES類別
#import <Foundation/Foundation.h>
@interface NSString (AES)
/**< 加密方法 */
- (NSString*)aci_encryptWithAES;
/**< 解密方法 */
- (NSString*)aci_decryptWithAES;
@end
複製程式碼
.m檔案 加密解密需要匯入這兩個標頭檔案(其實只匯入第二個就夠了)
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
複製程式碼
使用GTMBase64的話需要匯入#import "GTMBase64.h"
定義加密的Key和向量IV
static NSString *const PSW_AES_KEY = @"TESTPASSWORD";
static NSString *const AES_IV_PARAMETER = @"AES00IVPARAMETER";
@implementation NSString (AES)
- (NSString*)aci_encryptWithAES {
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
NSData *AESData = [self AES128operation:kCCEncrypt
data:data
key:PSW_AES_KEY
iv:AES_IV_PARAMETER];
NSString *baseStr_GTM = [self encodeBase64Data:AESData];
NSString *baseStr = [AESData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
NSLog(@"*****************\nGTMBase:%@\n*****************", baseStr_GTM);
NSLog(@"*****************\niOSCode:%@\n*****************", baseStr);
return baseStr_GTM;
}
- (NSString*)aci_decryptWithAES {
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
NSData *baseData_GTM = [self decodeBase64Data:data];
NSData *baseData = [[NSData alloc]initWithBase64EncodedString:self options:0];
NSData *AESData_GTM = [self AES128operation:kCCDecrypt
data:baseData_GTM
key:PSW_AES_KEY
iv:AES_IV_PARAMETER];
NSData *AESData = [self AES128operation:kCCDecrypt
data:baseData
key:PSW_AES_KEY
iv:AES_IV_PARAMETER];
NSString *decStr_GTM = [[NSString alloc] initWithData:AESData_GTM encoding:NSUTF8StringEncoding];
NSString *decStr = [[NSString alloc] initWithData:AESData encoding:NSUTF8StringEncoding];
NSLog(@"*****************\nGTMBase:%@\n*****************", decStr_GTM);
NSLog(@"*****************\niOSCode:%@\n*****************", decStr);
return decStr;
}
複製程式碼
AES加解密演算法
/**
* AES加解密演算法
*
* @param operation kCCEncrypt(加密)kCCDecrypt(解密)
* @param data 待操作Data資料
* @param key key
* @param iv 向量
*
* @return
*/
- (NSData *)AES128operation:(CCOperation)operation data:(NSData *)data key:(NSString *)key iv:(NSString *)iv {
char keyPtr[kCCKeySizeAES128 + 1]; //kCCKeySizeAES128是加密位數 可以替換成256位的
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
// IV
char ivPtr[kCCBlockSizeAES128 + 1];
bzero(ivPtr, sizeof(ivPtr));
[iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
size_t bufferSize = [data length] + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
// 設定加密引數
//(根據需求選擇什麼加密位數128or256,PKCS7Padding補碼方式之類的_(:з」∠)_,詳細的看下面吧)
CCCryptorStatus cryptorStatus = CCCrypt(operation, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
ivPtr,
[data bytes], [data length],
buffer, bufferSize,
&numBytesEncrypted);
if(cryptorStatus == kCCSuccess) {
NSLog(@"Success");
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
} else {
NSLog(@"Error");
}
free(buffer);
return nil;
}
複製程式碼
GTMBase64編碼
/**< GTMBase64編碼 */
- (NSString*)encodeBase64Data:(NSData *)data {
data = [GTMBase64 encodeData:data];
NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return base64String;
}
/**< GTMBase64解碼 */
- (NSData*)decodeBase64Data:(NSData *)data {
data = [GTMBase64 decodeData:data];
return data;
}
複製程式碼
完成!你就可以去跑,去跳,去做一個漂亮的倒掛金鉤了~
Demo下載地址:https://github.com/iOSAppleBea/AES_1
附:CCCryptorStatus構造
關於加密引數CCCryptorStatus,構造他可以使用CCCrypt
CCCryptorCreateWithMode
CCCryptorCreate
等好多種方法,構造時對引數的使用還是比較麻煩的,看文件對英語渣來說很辛苦,大概說一下看過CCCrypt
後瞭解的幾點
蘋果文件
/*!
@function CCCrypt
@abstract Stateless, one-shot encrypt or decrypt operation.
This basically performs a sequence of CCCrytorCreate(),
CCCryptorUpdate(), CCCryptorFinal(), and CCCryptorRelease().
@param alg Defines the encryption algorithm.
@param op Defines the basic operation: kCCEncrypt or kCCDecrypt.
@param options A word of flags defining options. See discussion
for the CCOptions type.
@param key Raw key material, length keyLength bytes.
加解密的金鑰
@param keyLength Length of key material. Must be appropriate
for the select algorithm. Some algorithms may
provide for varying key lengths.
引數解釋詳見蘋果文件中的一個Key Size的列舉
enum {
kCCKeySizeAES128 = 16,
kCCKeySizeAES192 = 24,
kCCKeySizeAES256 = 32,
kCCKeySizeDES = 8,
kCCKeySize3DES = 24,
kCCKeySizeMinCAST = 5,
kCCKeySizeMaxCAST = 16,
kCCKeySizeMinRC4 = 1,
kCCKeySizeMaxRC4 = 512,
kCCKeySizeMinRC2 = 1,
kCCKeySizeMaxRC2 = 128,
kCCKeySizeMinBlowfish = 8,
kCCKeySizeMaxBlowfish = 56,
};
@param iv Initialization vector, optional. Used for
Cipher Block Chaining (CBC) mode. If present,
must be the same length as the selected
algorithm's block size. If CBC mode is
selected (by the absence of any mode bits in
the options flags) and no IV is present, a
NULL (all zeroes) IV will be used. This is
ignored if ECB mode is used or if a stream
cipher algorithm is selected.
向量:大概意思說,此屬性可選,但只能用於CBC模式。
如果出現那麼他的長度必須和演算法的block size保持一致。
如果是因為預設選擇的CBC模式而且向量沒有定義,那麼向量會被定義為NULL。
如果選擇了ECB模式或是其他的流密碼演算法,之前所說的邏輯都不成立。
@param dataIn Data to encrypt or decrypt, length dataInLength
bytes.
@param dataInLength Length of data to encrypt or decrypt.
@param dataOut Result is written here. Allocated by caller.
Encryption and decryption can be performed
"in-place", with the same buffer used for
input and output.
@param dataOutAvailable The size of the dataOut buffer in bytes.
@param dataOutMoved On successful return, the number of bytes
written to dataOut. If kCCBufferTooSmall is
returned as a result of insufficient buffer
space being provided, the required buffer space
is returned here.
@result kCCBufferTooSmall indicates insufficent space in the dataOut
buffer. In this case, the *dataOutMoved
parameter will indicate the size of the buffer
needed to complete the operation. The
operation can be retried with minimal runtime
penalty.
kCCAlignmentError indicates that dataInLength was not properly
aligned. This can only be returned for block
ciphers, and then only when decrypting or when
encrypting with block with padding disabled.
kCCDecodeError Indicates improperly formatted ciphertext or
a "wrong key" error; occurs only during decrypt
operations.
*/
CCCryptorStatus CCCrypt(
CCOperation op, /* kCCEncrypt, etc. */編碼 or 解碼
CCAlgorithm alg, /* kCCAlgorithmAES128, etc. */
CCOptions options, /* kCCOptionPKCS7Padding, etc. */
const void *key,
size_t keyLength,
const void *iv, /* optional initialization vector */
const void *dataIn, /* optional per op and alg */
size_t dataInLength,
void *dataOut, /* data RETURNED here */
size_t dataOutAvailable,
size_t *dataOutMoved)
複製程式碼
Demo下載地址:github.com/iOSAppleBea…