最近一直做的项目由于都是金融股票方面的app,加密要求比较高,自己了解了一些加密相关的知识,给大家分享一下。
POST请求,https协议,以及苹果自己的SSKeyChain这些就不用多说了,应该都了解。
主要说一下非对称加密。他的数据传输过程是:明文通过接收人的公钥加密,传输给接收人,因为只有接收人拥有对应的私钥,别人不可能拥有或者不可能通过公钥推算出私钥,所传输过程中无法被中间人截获。只有拥有私钥的接收人才能解密得到原文。比如,在登录时在客户端生成随机密钥,然后使用公钥加密传输到服务端,服务端使用私钥解密得到随机密钥,此密钥就用于后续的AES加密/解密使用。通俗一点的说:前面的几种加密方法是:一把钥匙可以开对应的一把锁。而非对称加密是指:这把钥匙,在特定的情况下,才能打开它所对应的那把锁。例如:我拿着钥匙,在门口和屋里的管家对上暗号后(钥匙相当于公钥,你和屋里面的管家的暗号相当于私钥),得到里面人的允许并且里面的人知道我进来只是拿我的mac电脑的情况,才能打开门。
非对称加密的组成主要是RSA公钥和DSA私人密钥组成。
用某用户密钥加密后所得的信息,只能用该用户的解密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此如果公开了一对密钥中的一个,并不会危害到另外一个的秘密性质,这样说应该够好理解。
原理大致就是这样了。犹豫我现在主要做的是移动端的开发,咱们直接代码撸起来。看一下这个加密过程、
首先在自己的mac上装上openssl
OpenSSL安装步骤
下载
git clone git://git.openssl.org/openssl.git
安装
sudo ./config --prefix=/usr/local/openssl
.执行
make
make install
查看版本
openssl version
出现:
OpenSSL 0.9.8zh 14 Jan 2016
则表示安装ok。
加密过程中的思路是:
1、定义一个方法,把证书文件需要加密的数据传入一个方法中,生成一个公钥。
2、创建一个能够将数据进行base64加密的方法。将需要加密的文本通过base加密,加密完成后再调用公钥加密的方法对base加密后的数据进行二次加密。加密时是讲二进制数据分段,切片后进行加密再拼接到二进制数据的变量中
生成公钥和私钥:
生成1024位私钥 openssl genrsa -out private_key.pem 1024
根据私钥生成CSR文件 openssl req -new -key private_key.pem -out rsaCertReq.csr
根据私钥和CSR文件生成crt文件 openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt
为IOS端生成公钥der文件 openssl x509 -outform der -in rsaCert.crt -out public_key.der
将私钥导出为这p12文件 openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt
SecKeyRef _publicKey;
SecKeyRef _privateKey;
}@end@implementation HYBRSAEncrypt- (void)dealloc { if (nil != _publicKey) { CFRelease(_publicKey);
} if (nil != _privateKey) { CFRelease(_privateKey);
}
}#pragma mark - 加密相关//用本地证书加载公钥- (void)loadPublicKeyWithPath:(NSString *)derFilePath { NSData *derData = [[NSData alloc] initWithContentsOfFile:derFilePath]; if (derData.length > 0) {
[self loadPublicKeyWithData:derData];
} else { NSLog(@"load public key fail with path: %@", derFilePath);
}
}//加载公钥方法- (void)loadPublicKeyWithData:(NSData *)derData {
SecCertificateRef myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)derData);
SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
SecTrustRef myTrust;
OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);
SecTrustResultType trustResult; if (status == noErr) {
status = SecTrustEvaluate(myTrust, &trustResult);
}
SecKeyRef securityKey = SecTrustCopyPublicKey(myTrust); CFRelease(myCertificate); CFRelease(myPolicy); CFRelease(myTrust);
_publicKey = securityKey;
}//将文本内容加密- (NSString *)rsaEncryptText:(NSString *)text { NSData *encryptedData = [self rsaEncryptData:[text hdf_toData]]; NSString *base64EncryptedString = [NSString hdf_base64StringFromData:encryptedData
length:encryptedData.length]; return base64EncryptedString;
}//分段再加密数据- (NSData *)rsaEncryptData:(NSData *)data {
SecKeyRef key = _publicKey;
size_t cipherBufferSize = SecKeyGetBlockSize(key);
uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
size_t blockSize = cipherBufferSize - 11;
size_t blockCount = (size_t)ceil([data length] / (double)blockSize); NSMutableData *encryptedData = [[NSMutableData alloc] init] ; for (int i = 0; i < blockCount; i++) {
size_t bufferSize = MIN(blockSize,[data length] - i * blockSize); NSData *buffer = [data subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];
OSStatus status = SecKeyEncrypt(key,
kSecPaddingPKCS1,
(const uint8_t *)[buffer bytes],
[buffer length],
cipherBuffer,
&cipherBufferSize); if (status == noErr) { NSData *encryptedBytes = [[NSData alloc] initWithBytes:(const void *)cipherBuffer
length:cipherBufferSize];
[encryptedData appendData:encryptedBytes];
} else { if (cipherBuffer) {
free(cipherBuffer);
} return nil;
}
} if (cipherBuffer){
free(cipherBuffer);
} return encryptedData;
}
然后我们可以通过私钥解密。解密思路和加密过程相同。
#pragma mark - 解密相关- (void)loadPrivateKeyWithPath:(NSString *)p12FilePath password:(NSString *)p12Password { NSData *data = [NSData dataWithContentsOfFile:p12FilePath]; if (data.length > 0) { [self loadPrivateKeyWithData:data password:p12Password]; } else { NSLog(@"load private key fail with path: %@", p12FilePath); } }//生成私钥- (void)loadPrivateKeyWithData:(NSData *)p12Data password:(NSString *)p12Password { SecKeyRef privateKeyRef = NULL; NSMutableDictionary * options = [[NSMutableDictionary alloc] init]; [options setObject:p12Password forKey:(__bridge id)kSecImportExportPassphrase]; CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); OSStatus securityError = SecPKCS12Import((__bridge CFDataRef)p12Data, (__bridge CFDictionaryRef)options, &items); if (securityError == noErr && CFArrayGetCount(items) > 0) { CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0); SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity); securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef); if (securityError != noErr) { privateKeyRef = NULL; } } _privateKey = privateKeyRef; // CFRelease(items);}//调用下面方法进行解密,最后返回一个字符串- (NSString *)rsaDecryptText:(NSString *)text { NSData *data = [NSData hdf_base64DataFromString:text]; NSData *decryptData = [self rsaDecryptData:data]; NSString *result = [[NSString alloc] initWithData:decryptData encoding:NSUTF8StringEncoding]; return result; }//用私钥解密的方法,被上面方法调用- (NSData *)rsaDecryptData:(NSData *)data { SecKeyRef key = _privateKey; size_t cipherLen = [data length]; void *cipher = malloc(cipherLen); [data getBytes:cipher length:cipherLen]; size_t plainLen = SecKeyGetBlockSize(key) - 12; void *plain = malloc(plainLen); OSStatus status = SecKeyDecrypt(key, kSecPaddingPKCS1, cipher, cipherLen, plain, &plainLen); if (status != noErr) { return nil; } NSData *decryptedData = [[NSData alloc] initWithBytes:(const void *)plain length:plainLen]; return decryptedData; }@end
时间仓促,写的有点糙。有时间补充。