wuxiaohui0 2015-02-02
工作中遇到了安全传输问题,需要解决iOS和Android客户端跟java服务端的安全传输问题,结合对HTTPS的了解,便使用DES+RSA方式模拟HTTPS。在实现过程中,遇到了一些瓶颈,主要是保持平台兼容性的问题,Android和服务的还可以,统一使用javaAPI,但要包含iOS就比较麻烦了,参考了网上很多资料,忙了三四天,终于搞通了。
瓶颈卡在用openssl生成的pem文件在java没找到合适的API来解析获取私钥,最后是参考网上资料用openssl命令将pem文件转换为pkcs8格式文件才能读取。
MacOS上执行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