一、雜湊演算法(簽名算法/摘要)
雜湊演算法,又稱哈希函數,是一種單向加密算法。在資訊安全技術中,經常需要驗證消息的完整性,散列(Hash)函數提供了這一服務,它對不同長度的輸入消息,産生固定長度的輸出。因為其結果是不可逆的,既然是不可逆的,那麼當然不是用來加密的,而是簽名。
-
MD5
不可逆:MD5是不可逆轉的。
壓縮性:任意長度的資料,算出的MD5值長度都是固定的。
容易計算:從原資料計算出MD5值很容易。
抗修改性:對原資料進行任何改動,哪怕隻修改1個位元組,所得到的MD5值都有很大差別。
強抗碰撞:已知原資料和其MD5值,想找到一個具有相同MD5值的資料是非常困難的。
主要用于驗證,防止資訊被修。具體用途如:檔案校驗、數字簽名、鑒權協定。
-(NSString *)md5 {
if (!self) return nil;
const char *cStr = self.UTF8String;
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
NSMutableString *md5Str = [NSMutableString string];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; ++i) {
[md5Str appendFormat:@"%02x", result[i]];
}
return md5Str;
}
-
SHA
是由NISTNSA設計為同DSA一起使用的,它對長度小于264的輸入,産生長度為160bit的散列值,是以抗窮舉(brute-force)性更好。
SHA-1設計時基于和MD4相同原理,并且模仿了該算法。
SHA-1是由美國标準技術局(NIST)頒布的國家标準,是一種應用最為廣泛的Hash函數算法,也是目前最先進的加密技術,被政府部門和私營業主用來處理敏感的資訊。
SHA-1基于MD5,MD5又基于MD4。
- (NSString*) sha1
{
const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:self.length];
//使用對應的CC_SHA1,CC_SHA256,CC_SHA384,CC_SHA512的長度分别是20,32,48,64
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
//使用對應的CC_SHA256,CC_SHA384,CC_SHA512
CC_SHA1(data.bytes, data.length, digest);
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
[output appendFormat:@"%02x", digest[i]];
return output;
}
二、對稱算法
對稱式加密就是加密和解密使用同一個密鑰。資訊接收雙方都需事先知道密匙和加解密算法且其密匙是相同的,之後便是對資料進行加解密了。對稱加密算法用來對敏感資料等資訊進行加密。
-
AES
進階加密标準,目前美國國家安全局使用的,蘋果的鑰匙串通路采用的就AES加密。是現在公認的最安全的加密方式,是對稱密鑰加密中最流行的算法。
主要應用在關鍵資料和檔案的的保密同時又需要解密的情形,其加密密鑰和解密密鑰相同,根據密鑰長度分為128、192和256三種級别,密鑰長度越大安全性也就越大,但性能也就越低,根據實際業務的安全要求來決定就好。通常情況,對一些關鍵資料進行加密的對象都是字元串,加密結果也以字元串進行儲存,是以在設計接口的時候參數和傳回值均為字元串。
//AES128位加密 base64編碼 注:kCCKeySizeAES128點進去可以更換256位加密
-(NSString *)aes128Encrypt:(NSString *)key
{
char keyPtr[kCCKeySizeAES128+1];//
memset(keyPtr, 0, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSData* data = [self dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger dataLength = [data length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding|kCCOptionECBMode,
keyPtr,
kCCBlockSizeAES128,
NULL,
[data bytes],
dataLength,
buffer,
bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
NSString *stringBase64 = [resultData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]; // base64格式的字元串
return stringBase64;
}
free(buffer);
return nil;
}
//解密
-(NSString *)aes128Decrypt:(NSString *)key
{
char keyPtr[kCCKeySizeAES128 + 1];
memset(keyPtr, 0, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSData *data = [[NSData alloc] initWithBase64EncodedString:self options:NSDataBase64DecodingIgnoreUnknownCharacters];//base64解碼
NSUInteger dataLength = [data length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesCrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding|kCCOptionECBMode,
keyPtr,
kCCBlockSizeAES128,
NULL,
[data bytes],
dataLength,
buffer,
bufferSize,
&numBytesCrypted);
if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
return [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
}
free(buffer);
return nil;
}
-
DES
資料加密标準(現在用的比較少,因為它的加密強度不夠,能夠暴力破解)
- (NSString *) desEncrypt:(NSString *)key
{
NSString *ciphertext = nil;
const char *textBytes = [self UTF8String];
NSUInteger dataLength = [self length];
size_t bufferPtrSize = (dataLength + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
unsigned char* buffer = (unsigned char *)malloc(bufferPtrSize);;
memset(buffer, 0, bufferPtrSize);
Byte iv[] = {1,2,3,4,5,6,7,8};
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, // 加密/解密
kCCAlgorithmDES, // 加密根據哪個标準(des,3des,aes。。。。)
kCCOptionPKCS7Padding, // 選項分組密碼算法(des:對每塊分組加一次密 3DES:對每塊分組加三個不同的密)
[key UTF8String], //密鑰 加密和解密的密鑰必須一緻
kCCKeySizeDES, // DES 密鑰的大小(kCCKeySizeDES=8)
iv, // 可選的初始矢量
textBytes, dataLength,
buffer, bufferPtrSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
ciphertext = [[NSString alloc] initWithData:[data base64EncodedDataWithOptions:0] encoding:NSUTF8StringEncoding];
}
free(buffer);
return ciphertext;
}
//解密
- (NSString *) desDecrypt:(NSString*)key
{
NSData* cipherData = [[NSData alloc] initWithBase64EncodedString:self options:0];
NSUInteger dataLength = [self length];
size_t bufferPtrSize = (dataLength + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
unsigned char* buffer = (unsigned char *)malloc(bufferPtrSize);;
memset(buffer, 0, bufferPtrSize);
size_t numBytesDecrypted = 0;
Byte iv[] = {1,2,3,4,5,6,7,8};
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
[key UTF8String],
kCCKeySizeDES,
iv,
[cipherData bytes],
[cipherData length],
buffer,
bufferPtrSize,
&numBytesDecrypted);
NSString* plainText = nil;
if (cryptStatus == kCCSuccess) {
NSData* data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesDecrypted];
plainText = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
free(buffer);
return plainText;
}
三、非對稱算法
非對稱加密工作原理:
乙方生成一對密鑰(公鑰和私鑰)并将公鑰向其它方公開。
得到該公鑰的甲方使用該密鑰對機密資訊進行加密後再發送給乙方。
乙方再用自己儲存的另一把專用密鑰(私鑰)對加密後的資訊進行解密。乙方隻能用其專用密鑰(私鑰)解密由對應的公鑰加密後的資訊。
在傳輸過程中,即使攻擊者截獲了傳輸的密文,并得到了乙的公鑰,也無法破解密文,因為隻有乙的私鑰才能解密密文。同樣,如果乙要回複加密資訊給甲,那麼需要甲先公布甲的公鑰給乙用于加密,甲自己儲存甲的私鑰用于解密。
非對稱加密一般有兩種用途:
進行資料認證(鑒權)服務校驗,即對發送資料方是否是我們所期望的那個做驗證。私鑰加簽,公鑰驗簽。
對資料進行加密,公鑰加密,私鑰解密。由于非對稱加密算法的低效,是以各密碼機構主張對稱加密算法和非對稱加密算法結合,用對稱加密算法加密内容,用非對稱加密算法加密對稱算法的密鑰。在算法設計上,非對稱加密算法對待加密資料長度要求極為苛刻。比如,RSA算法要求待加密資料長度不得超過53個位元組。是以,非對稱加密主要用于交換對稱加密的秘密密鑰,而非資料内容上的加密。
- RSA
- 建立存儲密鑰檔案夾RSA
- 在該檔案夾目錄下執行
指令openssl
- 生成私鑰:
genrsa -out rsa_private_key.pem 1024
- 将私鑰轉成PKCS8的格式,格式轉好後立刻複制
pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt
- 生成公鑰:
rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
。
打開剛才的RSA檔案裡的
擷取公鑰rsa_public_key.pem
- 引入工具類 Objective-C-RSA,用于加密解密
NSString *pubkey = @"-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHNhQwlZs3zjic1m5rCwVZ9DEwPED9bgXvWRQVeRDA/iiZwbp1Z3xJI1ybu9IWzxBvmeh6Knilh36+MuRtMs3arVoIa3LgErPrYPDoMmEBfSloFiBh8MDmHzCM5pSU15qrVe5Ml4uTrazQhTuCi086Bj6Bmf70Bvoij+nC1WnLSwIDAQAB\n-----END PUBLIC KEY-----";
NSString *privkey = @"-----BEGIN PRIVATE KEY-----\nMIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMc2FDCVmzfOOJzWbmsLBVn0MTA8QP1uBe9ZFBV5EMD+KJnBunVnfEkjXJu70hbPEG+Z6HoqeKWHfr4y5G0yzdqtWghrcuASs+tg8OgyYQF9KWgWIGHwwOYfMIzmlJTXmqtV7kyXi5OtrNCFO4KLTzoGPoGZ/vQG+iKP6cLVactLAgMBAAECgYBaH5QYusYjBA/GnJgNo0nDfV73dHrubGUQ+FrGsCOtPA6AKQ3C6ZNnvzC5X8pW+Ux1QMrU4fv83wSu5XVEFbTcyRNY58l2ZE9oHYh3CDr0kLSqBUpSx1MjCk6pHwrYeIKVQtyKZpNjwc6o8Iop4Vz0f5YLxSrt58tx/JH0Ndlr8QJBAPrho7I3tbcfKjL9k+61+A5Y5uzOfjwuOJynjoEeWLv1JLjT4uU2F1hlrhE7RpNWgRWV9zAoUIjK7kOWicdf3fkCQQDLRpCTh8SWKITwKHXJGEw49/l7RjKtn38ju4SuLkEfGZCd9+P1RO5FNuDWxLbJrPLR8yxHo+2uggJ4Gg6D25RjAkEAtC8sn4oNc7jpWPfwsGh3AO7u47MmzNgxhql82tVNy6i0OB7N/euMdsuIag3VkWp2iWdMwoSh2q1M1LQgvlXnGQJAKHSTw3jKzCOmSXGT94CpctEPStRus5VBpWflgRDdjwX0fSvfp2mfjhDc8IFX641LCjO+RUe/vvJK8YImD2H9BwJANxMZFA135dBXNZ/lKPZ/5p2bBfeJ7M9qnDJJpsASsGKrwbSCQUl1Qcq1oUVqvN0Z+syerVPtTztyMqNkLuwp5g==\n-----END PRIVATE KEY-----";
NSString *originString = @"hello world!";
NSLog(@"Original string(%d): %@", (int)originString.length, originString);
// 公鑰加密
NSString *encWithPubKey = [RSA encryptString:originString publicKey:pubkey];
NSLog(@"Enctypted with public key: %@", encWithPubKey);
// 私鑰解密
NSString *decWithPrivKey = [RSA decryptString:encWithPubKey privateKey:privkey];
NSLog(@"Decrypted with private key: %@", decWithPrivKey);
// 私鑰加密
NSString *encWithPrivKey = [RSA encryptString:originString privateKey:privkey];
NSLog(@"Enctypted with private key: %@", encWithPrivKey);
// 公鑰解密
NSString *decWithPublicKey = [RSA decryptString:encWithPrivKey publicKey:pubkey];
NSLog(@"Decrypted with public key: %@", decWithPublicKey);
列印結果
2020-09-05 10:56:51.829078+0800 ModuleProject[8630:93898] Original string: hello world!
2020-09-05 10:56:51.849902+0800 ModuleProject[8630:93898] Enctypted with public key: msJnCtTPe3KCvsg4psupRx/8gtyIABBLgkEqb46wvROnTIl3NcaGE0GOR8hQ5mgUPDd+2RrnNilB0d+/C+lQoOiu1zir33sezSS+HEygt0LQhWbbn4ZkD46Z8QhQJEYHnS8WERLUHOen31BEaWy+eMRCcAQ41zKlKpfKHx0rDtI=
2020-09-05 10:56:51.861117+0800 ModuleProject[8630:93898] Decrypted with private key: hello world!
2020-09-05 10:56:51.955834+0800 ModuleProject[8630:93898] Enctypted with private key: f7RidCBDRJ7DRKiIP3IhpP8Ob7jIzRc+7aarLOVmj4haRLmvI379rOxKtwRxbSzQV63vj3MIzUIuvpfF2c16osb1Is16PaxIj70ffZKBRzRx60OCy0DB5ZZGzE/GFVOdEkvTTXbGydfysxohUWZkB1VZmMZrNw1wTtkSK9bBVdM=
2020-09-05 10:56:51.984258+0800 ModuleProject[8630:93898] Decrypted with public key: hello world!