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

标签: ios android java | 发表时间:2015-02-02 17:36 | 作者:geniuswxk
出处:http://www.iteye.com
工作中遇到了安全传输问题,需要解决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

已有 1 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [ios android java] 推荐:

RAP Mobile:用Java开发iOS和Android应用

- - ITeye资讯频道
自从Web技术如HTML5、JavaScript、CSS在移动编程上日益流行后,Java在编写跨平台移动应用上似乎不太流行了. 因此, EclipseSoure公司近日推出了 RAP Mobile,希望能够作为Java跨平台开发的一个替代方案. RAP Mobile提供了一个强大的Widget工具包,可用于渲染(render)原生的iOS和Android widget.

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

- - 移动开发 - ITeye博客
工作中遇到了安全传输问题,需要解决iOS和Android客户端跟java服务端的安全传输问题,结合对HTTPS的了解,便使用DES+RSA方式模拟HTTPS. 在实现过程中,遇到了一些瓶颈,主要是保持平台兼容性的问题,Android和服务的还可以,统一使用java API,但要包含iOS就比较麻烦了,参考了网上很多资料,忙了三四天,终于搞通了.

前Sun开发人员为Android,iOS等其他移动平台提供JAVA的WORA支持

- - InfoQ cn
2012年,在以色列出现了一个名为 Codename one的公司,该公司旨在生成一种新的Java SDK,该SDK将允许Java开发人员通过一个单一的代码库就能为包括iOS,Android,BlackBerry和Windows Phone等一系列的移动设备编写本地应用. 对于iOS,Codename one通过自己的云服务器先将Java代码转换成C或者Objective C代码,然后再将转换后的源代码编译成本地应用程序.

MIUI评测:iOS身,Android心

- gaochao - 互联网的那点事
百度要推出自己的移动操作系统,江湖传闻叫“秋实”. 我们这里老调重弹,回过头温习一下同样基于Android的人气很高的MIUI. MIUI是一款很养眼的Android ROM,借鉴了大量的iOS审美元素. 如果你怀念或向往iOS的外观和感觉,MIUI绝对是不二之选. 以下是笔者在HTC Desire上运行MIUI的体验报告.

客觀評 Android、iOS、WP7

- chitsaou - Trawler Computer, FM207.NET
半年多前,我曾經評價過 Android 和 iOS 的市場發展,雖然發展至今,文章內容可見反映過去,但未來卻變得不可預料. 一年多前,Android 並未像現在這樣熱起來,所以我覺得,盲目支持 iPhone 的一群「果粉」,他們很愚蠢,但時至今日,支持 Android 陣營的用家似乎更盲目. 故此,希望能以客觀的角度分析一下各移動操作系統的利與弊,同時希望各位不要盲目喜歡自己的手機,要多加以分析,以下逐點評論.

iOS 开发笔记-andriod/java/iOS三方AES通用加密 - jiangys

- - 博客园_首页
AES在线加解密验证工具:  http://www.seacha.com/tools/aes.html. AES加密有多种算法模式,下面提供两套模式的可用源码. 将数据进行Base64解码. 一、CBC(Cipher Block Chaining,加密块链)模式. 是一种循环模式,前一个分组的密文和当前分组的明文异或操作后再加密,这样做的目的是增强破解难度..

Java/Android编码规范

- - CSDN博客推荐文章
1.        为什么需要编码规范?. 编码规范对于程序员而言尤为重要,有以下几个原因:. l        一个软件的生命周期中,80%的花费在于维护. l        几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护. l        编码规范可以改善软件的可读性,可以让程序员尽快而彻底地理解新的代码.

Android中Java和JavaScript交互

- - 极客521 | 极客521
Android提供了一个很强大的WebView控件用来处理Web网页,而在网页中,JavaScript又是一个很举足轻重的脚本. 本文将介绍如何实现Java代码和Javascript代码的相互调用. 实现Java和js交互十分便捷. WebView开启JavaScript脚本执行. WebView设置供JavaScript调用的交互接口.

iOS 7已占iOS系统60%,Android相形见绌

- - 互联网的一些事-关注互联网产品管理,交流产品设计、用户体验心得
  现在已经有几亿的iPhone、iPad和iPod touch设备被用户使用,而用户们最近的一个一致举动,莫过于安装iOS 7了. 在上个星期三,苹果发布了其最新的移动操作系统iOS 7,而截至9月23日,iOS 7的安装率已经达到了60%. 根据网络公司的数据显示,在9月19日这个数字已接近了40%,而到这周一中午,iOS 7的装机率已经达到了60%.

如何在iOS与Android间移植APP

- plidezus - 雪鸮的啁啾
除了像”I am rich”这种定点打击苹果烧包族的APP外,大多数应用都会尽量覆盖包含尽可能多的用户. 这就需要考虑在iOS和Android两种主流操作系统间移植的问题. 如果为各个平台量身定做界面,就能让用户利用以往的使用习惯快速学习. 但为多个平台设计各异的界面毕竟是需要工作量的. 如何才能在跨平台移植的时候只做那些最有必要的工作呢.