`

iOS、Android、java服务端 DES+RSA安全传输统一实现

阅读更多
工作中遇到了安全传输问题,需要解决iOS和Android客户端跟java服务端的安全传输问题,结合对HTTPS的了解,便使用DES+RSA方式模拟HTTPS。在实现过程中,遇到了一些瓶颈,主要是保持平台兼容性的问题,Android和服务的还可以,统一使用java API,但要包含iOS就比较麻烦了,参考了网上很多资料,忙了三四天,终于搞通了。
瓶颈卡在用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
分享到:
评论
3 楼 a30292330 2015-07-12  
那怎么办?难道有的版本不行?
2 楼 geniuswxk 2015-02-05  
这个地方后来又发现一个问题,Android和Java服务端RSA加密解密的方式有所不同,好像是虚拟机的实现方式不一样,所以Android还不能直接用这套东西
1 楼 geniuswxk 2015-02-02  
给自己点个赞

相关推荐

Global site tag (gtag.js) - Google Analytics