工作中遇到了安全传输问题,需要解决iOS和Android客户端跟java服务端的安全传输问题,结合对HTTPS的了解,便使用DES+RSA方式模拟HTTPS。在实现过程中,遇到了一些瓶颈,主要是保持平台兼容性的问题,Android和服务的还可以,统一使用java API,但要包含iOS就比较麻烦了,参考了网上很多资料,忙了三四天,终于搞通了。
瓶颈卡在用openssl生成的pem文件在java没找到合适的API来解析获取私钥,最后是参考网上资料用openssl命令将pem文件转换为pkcs8格式文件才能读取。
Mac OS上执行openssl命令操作
Android及java调用API
iOS调用API(其中有网上直接copy来的代码,在此多谢网友分享)
参考网址:
http://blog.iamzsx.me/show.html?id=155002
http://shuany.iteye.com/blog/730910
瓶颈卡在用openssl生成的pem文件在java没找到合适的API来解析获取私钥,最后是参考网上资料用openssl命令将pem文件转换为pkcs8格式文件才能读取。
Mac OS上执行openssl命令操作
- 1)创建私钥
- openssl genrsa -out private_key.pem 1024
- 2)创建证书请求(按照提示输入信息)
- openssl req -new -out cert.csr -key private_key.pem
- 3)自签署根证书
- openssl x509 -req -in cert.csr -out public_key.der -outform der -signkey private_key.pem -days 3650
- 4)用java代码要从这个文件中得到想要的priavtekey 可以先用命令(就被这东西卡住了)
- openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key.pem -out private_pkcs8_der.key -nocrypt
Android及java调用API
- import java.io.ByteArrayOutputStream;
- import java.io.FileInputStream;
- import java.math.BigInteger;
- import java.security.Key;
- import java.security.KeyFactory;
- import java.security.KeyPair;
- import java.security.KeyPairGenerator;
- import java.security.PrivateKey;
- import java.security.PublicKey;
- import java.security.cert.Certificate;
- import java.security.cert.CertificateFactory;
- import java.security.interfaces.RSAPrivateKey;
- import java.security.interfaces.RSAPublicKey;
- import java.security.spec.PKCS8EncodedKeySpec;
- import java.util.HashMap;
- import javax.crypto.Cipher;
- import javax.crypto.SecretKey;
- import javax.crypto.SecretKeyFactory;
- import javax.crypto.spec.DESKeySpec;
- import sun.misc.BASE64Decoder;
- import sun.misc.BASE64Encoder;
- public class Crypt {
- static BASE64Decoder decoder = new BASE64Decoder();
- static BASE64Encoder encoder = new BASE64Encoder();
- static String DES = "DES";
- static String RSA = "RSA";
- static String encode = "UTF-8";//保持平台兼容统一使用utf-8
- //私钥文件路径
- static String privateFile = "/XXX/private_pkcs8_der.key";
- //公钥文件路径
- static String publicFile = "/XXX/public_key.der";
- //des 加密
- private static byte [] encryptByteDES(byte[] byteD,String strKey) throws Exception {
- return doEncrypt(byteD, getKey(strKey), DES);
- }
- //des 解密
- private static byte [] decryptByteDES(byte[] byteD,String strKey) throws Exception {
- return doDecrypt(byteD, getKey(strKey), DES);
- }
- public static SecretKey getKey(String strKey) throws Exception {
- DESKeySpec desKeySpec = new DESKeySpec(strKey.getBytes());
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
- SecretKey sk = keyFactory.generateSecret(desKeySpec);
- return sk;
- }
- //pkcs8_der.key文件为私钥 只能保存在服务端
- //public_key.der为公钥文件,保存在客户端
- public static void main(String[] args) throws Exception {
- String text = "ceshishuuju测试数据ceshishuuju测试数据";
- String pwd="12345678";
- //客户端加密
- HashMap<String, String> data = DESAndRSAEncrypt(text.getBytes(encode),pwd);
- System.out.println("pwd RSA加密后base64:"+data.get("key"));
- System.out.println("text DES加密后base64:"+data.get("data"));
- //服务端解密
- String textDecrypt = DESAndRSADecrypt(data);
- System.out.println("未处理原文:"+text);
- System.out.println("解密后数据:"+textDecrypt);
- // generateKeyPair();
- }
- //客户端加密
- static HashMap<String, String> DESAndRSAEncrypt(byte[] dataToEncypt,String pwd) throws Exception{
- byte[] encryptData = encryptByteDES(dataToEncypt, pwd);
- String dataBase64 = encoder.encode(encryptData);
- byte[] encryptKey = RSAEncrypt(pwd.getBytes(encode));
- String keyBase64 = encoder.encode(encryptKey);
- HashMap<String, String> data = new HashMap<String, String>();
- data.put("data", dataBase64);
- data.put("key", keyBase64);
- return data;
- }
- //服务端解密
- static String DESAndRSADecrypt(HashMap<String, String> data) throws Exception {
- String dataBase64 = data.get("data");
- String keyBase64 = data.get("key");
- byte[] encryptedData = decoder.decodeBuffer(dataBase64);
- byte[] encryptedKey = decoder.decodeBuffer(keyBase64);
- byte[] decryptedKey= RSADecrypt(encryptedKey);
- String pwd = new String(decryptedKey,encode);
- System.out.println("DES密码:"+pwd);
- byte[] decryptedData = decryptByteDES(encryptedData, pwd);
- String textDecrypt = new String(decryptedData,encode);
- return textDecrypt;
- }
- //公钥加密
- public static byte[] RSAEncrypt(byte[] plainText) throws Exception{
- //读取公钥
- CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
- FileInputStream bais = new FileInputStream(publicFile);
- Certificate cert = certificatefactory.generateCertificate(bais);
- bais.close();
- PublicKey puk = cert.getPublicKey();
- // System.out.println("公钥base64:"+encoder.encode(puk.getEncoded()));
- return doEncrypt(plainText, puk, RSA);
- }
- //私钥解密
- public static byte[] RSADecrypt(byte[] encryptData) throws Exception{
- FileInputStream in = new FileInputStream(privateFile);
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- byte[] tmpbuf = new byte[1024];
- int count = 0;
- while ((count = in.read(tmpbuf)) != -1) {
- bout.write(tmpbuf, 0, count);
- }
- in.close();
- //读取私钥
- KeyFactory keyFactory = KeyFactory.getInstance(RSA);
- PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(bout.toByteArray());
- PrivateKey prk = keyFactory.generatePrivate(privateKeySpec);
- // System.out.println("私钥base64:"+encoder.encode(prk.getPrivateExponent().toByteArray()));
- return doDecrypt(encryptData, prk, RSA);
- }
- /**
- * 执行加密操作
- * @param data 待操作数据
- * @param key Key
- * @param type 算法 RSA or DES
- * @return
- * @throws Exception
- */
- public static byte[] doEncrypt(byte[] data,Key key,String type) throws Exception{
- Cipher cipher = Cipher.getInstance(type);
- cipher.init(Cipher.ENCRYPT_MODE, key);
- return cipher.doFinal(data);
- }
- /**
- * 执行解密操作
- * @param data 待操作数据
- * @param key Key
- * @param type 算法 RSA or DES
- * @return
- * @throws Exception
- */
- public static byte[] doDecrypt(byte[] data,Key key,String type) throws Exception{
- Cipher cipher = Cipher.getInstance(type);
- cipher.init(Cipher.DECRYPT_MODE, key);
- return cipher.doFinal(data);
- }
- public static void generateKeyPair() throws Exception{
- KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
- kpg.initialize(1024); // 指定密钥的长度,初始化密钥对生成器
- KeyPair kp = kpg.generateKeyPair(); // 生成密钥对
- RSAPublicKey puk = (RSAPublicKey) kp.getPublic();
- RSAPrivateKey prk = (RSAPrivateKey) kp.getPrivate();
- BigInteger e = puk.getPublicExponent();
- BigInteger n = puk.getModulus();
- BigInteger d = prk.getPrivateExponent();
- BASE64Encoder encoder = new BASE64Encoder();
- System.out.println("public key:\n"+encoder.encode(n.toByteArray()));
- System.out.println("private key:\n"+encoder.encode(d.toByteArray()));
- }
- }
iOS调用API(其中有网上直接copy来的代码,在此多谢网友分享)
- #import <Foundation/Foundation.h>
- @interface WDCrypto : NSObject
- /*
- * DES加密数据 RSA加密DES密钥 公钥证书路径(默认mainBundle下 public_key.der)
- * 返回加密后数据base64编码 {key:xxx,data:XXX}
- */
- +(NSDictionary*)encryptWithDESAndRSA:(NSData*) data withKey:(NSString*)key keyPath:(NSString*)keyPath;
- /*
- * RSA加密 输入NSString类型数据 公钥证书路径(默认mainBundle下 public_key.der)
- * 返回加密后数据base64编码
- */
- +(NSString*)RSAEncryptData:(NSString*)text keyPath:(NSString*)keyPath;
- /*
- * RSA加密 输入NSString类型数据 公钥证书路径(默认mainBundle下 public_key.der)
- * 返回加密后数据base64编码
- */
- +(NSData*)RSAEncryptToData:(NSString*)text keyPath:(NSString*)keyPath;
- /*
- * DES加密 输入NSString类型数据和NSString加密密钥 返回加密后数据base64编码
- */
- +(NSString*)DESEncryptWithBase64:(NSString*)str key:(NSString*)key;
- /*
- * DES加密 输入密文base64和NSString解密密钥 返回解密后数据明文
- */
- +(NSString*)DESDecryptBase64:(NSString*)base64 key:(NSString*)key;
- /*
- * DES加密 输入NSData类型数据和NSString加密密钥 返回加密后数据
- */
- +(NSData *)DESEncrypt:(NSData *)data WithKey:(NSString *)key;
- /*
- * DES加密 输入NSData类型密文和NSString解密密钥 返回解密后数据
- */
- +(NSData *)DESDecrypt:(NSData *)data WithKey:(NSString *)key;
- @end
- /*
- * RSA加密 公钥文件默认为public_key.der
- */
- @interface WDRSACrypt : NSObject {
- SecKeyRef publicKey;
- SecCertificateRef certificate;
- SecPolicyRef policy;
- SecTrustRef trust;
- size_t maxPlainLen;
- }
- /*
- *指定证书路径
- */
- - (id)initWithKeyPath:(NSString*) publicKeyPath;
- - (NSData *) encryptWithData:(NSData *)content;
- - (NSData *) encryptWithString:(NSString *)content;
- @end
- #import "WDCrypto.h"
- #import <CommonCrypto/CommonCryptor.h>
- @implementation WDCrypto
- //客户端加密
- +(NSDictionary*)encryptWithDESAndRSA:(NSData*) data withKey:(NSString*)key keyPath:(NSString*)keyPath{
- //rsa
- NSString* encryptedKey = [WDCrypto RSAEncryptData:key keyPath:keyPath];
- //des
- NSData* encryptedData = [WDCrypto DESEncrypt:data WithKey:key];
- NSString* encryptedBase64 = [encryptedData base64Encoding];
- NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:encryptedKey,@"key",encryptedBase64,@"data",nil];
- return dict;
- }
- +(NSString*)RSAEncryptData:(NSString*)text keyPath:(NSString*)keyPath{
- NSData* data = [WDCrypto RSAEncryptToData:text keyPath:keyPath];
- NSString* encryptedKey = [data base64Encoding];
- return encryptedKey;
- }
- +(NSData*)RSAEncryptToData:(NSString*)text keyPath:(NSString*)keyPath{
- NSData* encryptData = nil;
- if (!keyPath) {
- keyPath = [[NSBundle mainBundle] pathForResource:@"public_key" ofType:@"der"];
- }
- WDRSACrypt *rsa = [[WDRSACrypt alloc] initWithKeyPath:keyPath];
- if (rsa != nil) {
- encryptData = [rsa encryptWithString:text];
- }else {
- NSLog(@"init rsa error");
- }
- return encryptData;
- }
- +(NSString*)DESEncryptWithBase64:(NSString*)str key:(NSString*)key{
- NSData* data = [str dataUsingEncoding:(NSUTF8StringEncoding)];
- NSData* encryptData = [WDCrypto DESEncrypt:data WithKey:key];
- NSString* base64 = [encryptData base64Encoding];
- return base64;
- }
- +(NSString*)DESDecryptBase64:(NSString*)base64 key:(NSString*)key{
- NSData* encryptData = [[NSData alloc] initWithBase64Encoding:base64];
- NSData* data = [WDCrypto DESDecrypt:encryptData WithKey:key];
- NSString* decryptStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- return decryptStr;
- }
- /******************************************************************************
- 函数名称 : + (NSData *)DESEncrypt:(NSData *)data WithKey:(NSString *)key
- 函数描述 : 文本数据进行DES加密
- 输入参数 : (NSData *)data
- (NSString *)key
- 输出参数 : N/A
- 返回参数 : (NSData *)
- 备注信息 : 此函数不可用于过长文本
- ******************************************************************************/
- + (NSData *)DESEncrypt:(NSData *)data WithKey:(NSString *)key
- {
- char keyPtr[kCCKeySizeAES256+1];
- bzero(keyPtr, sizeof(keyPtr));
- [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
- NSUInteger dataLength = [data length];
- size_t bufferSize = dataLength + kCCBlockSizeAES128;
- void *buffer = malloc(bufferSize);
- size_t numBytesEncrypted = 0;
- CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
- kCCOptionPKCS7Padding | kCCOptionECBMode,
- keyPtr, kCCBlockSizeDES,
- NULL,
- [data bytes], dataLength,
- buffer, bufferSize,
- &numBytesEncrypted);
- if (cryptStatus == kCCSuccess) {
- return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
- }
- free(buffer);
- return nil;
- }
- /******************************************************************************
- 函数名称 : + (NSData *)DESEncrypt:(NSData *)data WithKey:(NSString *)key
- 函数描述 : 文本数据进行DES解密
- 输入参数 : (NSData *)data
- (NSString *)key
- 输出参数 : N/A
- 返回参数 : (NSData *)
- 备注信息 : 此函数不可用于过长文本
- ******************************************************************************/
- + (NSData *)DESDecrypt:(NSData *)data WithKey:(NSString *)key
- {
- char keyPtr[kCCKeySizeAES256+1];
- bzero(keyPtr, sizeof(keyPtr));
- [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
- NSUInteger dataLength = [data length];
- size_t bufferSize = dataLength + kCCBlockSizeAES128;
- void *buffer = malloc(bufferSize);
- size_t numBytesDecrypted = 0;
- CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES,
- kCCOptionPKCS7Padding | kCCOptionECBMode,
- keyPtr, kCCBlockSizeDES,
- NULL,
- [data bytes], dataLength,
- buffer, bufferSize,
- &numBytesDecrypted);
- if (cryptStatus == kCCSuccess) {
- return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
- }
- free(buffer);
- return nil;
- }
- @end
- @implementation WDRSACrypt
- - (id)initWithKeyPath:(NSString*) publicKeyPath{
- self = [super init];
- if (publicKeyPath == nil) {
- NSLog(@"Can not find pub.der");
- return nil;
- }
- NSData *publicKeyFileContent = [NSData dataWithContentsOfFile:publicKeyPath];
- if (publicKeyFileContent == nil) {
- NSLog(@"Can not read from pub.der");
- return nil;
- }
- certificate = SecCertificateCreateWithData(kCFAllocatorDefault, ( __bridge CFDataRef)publicKeyFileContent);
- if (certificate == nil) {
- NSLog(@"Can not read certificate from pub.der");
- return nil;
- }
- policy = SecPolicyCreateBasicX509();
- OSStatus returnCode = SecTrustCreateWithCertificates(certificate, policy, &trust);
- if (returnCode != 0) {
- NSLog(@"SecTrustCreateWithCertificates fail. Error Code: %ld", returnCode);
- return nil;
- }
- SecTrustResultType trustResultType;
- returnCode = SecTrustEvaluate(trust, &trustResultType);
- if (returnCode != 0) {
- NSLog(@"SecTrustEvaluate fail. Error Code: %ld", returnCode);
- return nil;
- }
- publicKey = SecTrustCopyPublicKey(trust);
- if (publicKey == nil) {
- NSLog(@"SecTrustCopyPublicKey fail");
- return nil;
- }
- maxPlainLen = SecKeyGetBlockSize(publicKey) - 12;
- return self;
- }
- - (NSData *) encryptWithData:(NSData *)content {
- size_t plainLen = [content length];
- if (plainLen > maxPlainLen) {
- NSLog(@"content(%ld) is too long, must < %ld", plainLen, maxPlainLen);
- return nil;
- }
- void *plain = malloc(plainLen);
- [content getBytes:plain
- length:plainLen];
- size_t cipherLen = 128; // 当前RSA的密钥长度是128字节
- void *cipher = malloc(cipherLen);
- OSStatus returnCode = SecKeyEncrypt(publicKey, kSecPaddingPKCS1, plain,
- plainLen, cipher, &cipherLen);
- NSData *result = nil;
- if (returnCode != 0) {
- NSLog(@"SecKeyEncrypt fail. Error Code: %ld", returnCode);
- }
- else {
- result = [NSData dataWithBytes:cipher
- length:cipherLen];
- }
- free(plain);
- free(cipher);
- return result;
- }
- - (NSData *) encryptWithString:(NSString *)content {
- return [self encryptWithData:[content dataUsingEncoding:NSUTF8StringEncoding]];
- }
- - (void)dealloc{
- CFRelease(certificate);
- CFRelease(trust);
- CFRelease(policy);
- CFRelease(publicKey);
- }
- @end
参考网址:
http://blog.iamzsx.me/show.html?id=155002
http://shuany.iteye.com/blog/730910