一、散列算法(签名算法/摘要)
散列算法,又称哈希函数,是一种单向加密算法。在信息安全技术中,经常需要验证消息的完整性,散列(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!