Namespaces

Variants
Actions

Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries over the next few weeks. Thanks for all your past and future contributions.

使用BouncyCastal进行RSA加解密算法处理

From Wiki
Jump to: navigation, search
Article Metadata

代码示例
文章
Amazing1100 在 15 Apr 2013 创建
最后由 hamishwillee 在 24 Jul 2013 编辑

Contents

需求

在Series 40中越来越多的CS应用,而且很多的在进行用户名,密码等信息验证时,都要求客户端使用服务器端给你的公钥对相关私密信息进行RSA加密后再发送到服务器端,然后服务器端再使用私钥进行解密,那么如何在Series 40中实现RSA加密就显得尤为重要了。


关于RSA

首先我们了解下什么是RSA加密算法: RSA公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。

 Rsa-process.jpg

在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然秘密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK。正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA 密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA对话密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要。 RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现在的三十多年里,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。

Nokia SDK for Java 2.0 限制

在Nokia SDK for Java 2.0中是支持” SATSA-CRYPTO API”的,所以我们可以通过它来进行一系列算法的加解密工作,比如对称算饭:DES, 3DES/DESede, AES,非对称算法:RSA等。 但是我们知道在进行数据加密时,我们必须提供一个正确的密钥,然后转化为Key对象,我们才能在代码中使用它进行数据的加密,通过代码形式如下:

Key key = new SecretKeySpec(keyBits, 0, keyBits.length, "AES");
cipher.init(Cipher.ENCRYPT_MODE, key);

但是”SecretKeySpec”这个类仅仅能被用于DES, AES等对称加密算法的密钥对象的生产,SATSA-CRYPTO并不支持使用公钥私钥对对一段消息进行加密,而且Nokia SDK for Java 2.0中是不支持SATSA-PKI的, 所以对于RSA这种非对称加密,那么我们必须另辟它径。

关于bouncy castle

Bouncy Castle 是一种用于 Java 平台的开放源码的轻量级密码术包。它支持大量的密码术算法,并提供 JCE 1.2.1 的实现。因为 Bouncy Castle 被设计成轻量级的,所以从 J2SE 1.4 到 J2ME(包括 MIDP)平台,它都可以运行。它是在 MIDP 上运行的唯一完整的密码术包。 我们可以通过它来实现我们想要的RSA加解密,那么首先我们看下如下配置它:

下载jar包

你可以到下面的链接中下载最新版本的jar包,在这里我们选择针对J2me的轻量级版本。 http://www.bouncycastle.org/latest_releases.html

配置

下载完成后,你需要把这个Jar添加到build path里面。 在Nokia IDE for JavaMe这个基于Eclipse的集成开发环境中,你可以添加,如下图:

Add-bouncycastal-lib.png

BouncyCastal RSA加解密相关API介绍

描述
org.bouncycastle.crypto.AsymmetricBlockCipher 一个非对称加密算法的接口,RSAEngine等算法都集成于它。
org.bouncycastle.crypto.CipherParameters 密钥的接口类,封装了密钥的相关成员属性等信息。
org.bouncycastle.crypto.encodings.PKCS1Encoding 一种编码方式,RSA加密所支持的Padding模式之一,还有RAW,OAEP等。
org.bouncycastle.crypto.engines.RSAEngine RSA加密的engine类,加解密工作都由它完成。
org.bouncycastle.crypto.params.RSAKeyParameters 集成于CipherParameters,用于公钥。
org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters 集成于CipherParameters,用于私钥。
org.bouncycastle.util.encoders.Hex 用来进行16进制的相关转化。

Demo演示

至此,有了上面的工作的后,我们就可以尝试使用BouncyCastal这个第三方库API来进行RSA的加解密了,下面我们来看一个Demo。

你可以从这里下载这个Demo File:BCEncreptTest.zip

创建公钥- RSAKeyParameters对象:

	private RSAKeyParameters getPubKey(String pubKey) {
RSAKeyParameters rsaPubKeyParam = null;
if (pubKey != null) {
BigInteger mypubkey_modulus = null;
BigInteger mypubkey_exponent = null;
 
try {
if(HexParam){
mypubkey_modulus = new BigInteger(module_hex, 16);
mypubkey_exponent = new BigInteger(exponent_hex, 16);
}
else{
mypubkey_modulus = new BigInteger(module_decimal, 10);
mypubkey_exponent = new BigInteger(exponent_decimal, 10);
}
 
// False stands for Encrypt
rsaPubKeyParam = new RSAKeyParameters(false, mypubkey_modulus, mypubkey_exponent);
System.out.println("Generate public key param Done !");
} catch (Exception e) {
System.out.println(e.toString());
}
 
}
return rsaPubKeyParam;
}


使用RSAEngine进行RSA加密:

		AsymmetricBlockCipher eng = new RSAEngine();  // RAW
//eng = new PKCS1Encoding(eng); //PKCS1
//eng = new OAEPEncoding(eng); //OAEP
 
eng.init(true, rsapubKey);
 
System.out.println("The String to be Encypted is: " + plainText);
 
byte[] inputdata = Hex.encode(plainText.getBytes());
 
try
{
outputdata = eng.processBlock(inputdata, 0, inputdata.length);
}
catch (Exception e)
{
System.out.println(e.toString());
}

从代码中可以看出,这里有3中padding模式,我们需要根据需要进行设置,并且保证加密和解密时,使用的是相同的模式。

创建私钥- RSAPrivateCrtKeyParameters 对象:

	private RSAKeyParameters getPriKey() {
BigInteger mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16);
BigInteger pubExp = new BigInteger("11", 16);
BigInteger privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16);
BigInteger p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16);
BigInteger q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16);
BigInteger pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16);
BigInteger qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16);
BigInteger crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16);
 
RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef);
 
return privParameters;
}


使用RSAEngine进行RSA解密:

	private byte[] rsaDecrypt(byte[] plainTextByte,CipherParameters privParameters) {
 
byte[] outputdata = null;
 
AsymmetricBlockCipher eng = new RSAEngine(); // RAW
//eng = new PKCS1Encoding(eng); //PKCS1
//eng = new OAEPEncoding(eng); //OAEP
 
eng.init(false, privParameters);
 
try
{
outputdata = eng.processBlock(plainTextByte, 0, plainTextByte.length);
}
catch (Exception e)
{
System.out.println("Decrypt error: " + e.toString());
}
 
return outputdata;
}


Log输出:

Rsa-demo-log.jpg

RSA算法对明文的Block的长度是有限制的,我们可以通过”RSAEngine. getInputBlockSize()”来获取允许的块的大小,比如我们这里获取出来的是127字节,我们进行加密的明文的长度不能超过此长度限制,如果超过那么我们必须进行分段处理, 然后才能进行加密,这一点很重要,请谨记。

需要注意,由于RSA非对称算法相对于DES等对称算法需要的系统性能和时间要求都高很多,所以一般我们只是用来保护最私密的数据,或者与AES等算饭混合使用。


最后我们看到,BouncyCastal这个库是较大的超过1M,对于很多Series 40手机,2M的包大小的限制,我们必须在打包时,进行混淆处理, 你可以使用Proguard,经测试,加入你仅仅使用RSA等加密API,混淆后的大小一般只有几十K,完全满足需要。

This page was last modified on 24 July 2013, at 10:26.
353 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×