RSA加密数据Ukey解密

背景

1977年,Ronald Rivest,Adi Shamir和Leonard Adleman提出了一种实现方案,即RSA;它后来变成了非对称密码方案中使用最广泛的一种。RSA也成为Rivest-Shamri-Adkeman算法,他是目前最广泛的一种非对称密钥方案,不过椭圆曲线和离散对数方案也逐渐普及。在实际中RSA应用广泛,但是我们却常用于:

@数据小片段的加密,尤其用于密钥传输

@数字签名,比如Internet上的数字证书。

写这篇文章的目的当前也是有自己记录的背景:使用Android手机从服务器上拿到Ukey的公钥-----Android手机使用公钥加密随机生成的密钥--------通过无线传送给Ukey------Ukey调用自己的私钥机密获取随机密钥,建立通信。

如果只是想测试java公私钥或者openssl,可以转到http://blog.csdn.net/chaijunkun/article/details/7275632,下面的内容就不适合了。

---------------------------------------分割----------------------------------------------------------------------

遇上的问题在java中如何装载Ukey生成的公钥,java环境下使用的是openssl密码环境,这里当然要感谢Eric A. Young和Tim J. Hudson是他们给我们带来了极大的方便,缺点是让我们看不见更多的底层,和RSA的运行机制。

首先说一下常规:

/**
 * 随机生成密钥对,采用DER编码格式
 * 一定要注意的是:publicKey生成的为162 bytes
 * 这里的publicKey不仅仅包含了128密钥信息,还有编码和序列等信息
 * 这个publicKey结构我查不到
 */
public void genKeyPair(){
	KeyPairGenerator keyPairGen= null;
	try {
		keyPairGen= KeyPairGenerator.getInstance("RSA");
	} catch (NoSuchAlgorithmException e) {
		e.printStackTrace();
	}
	keyPairGen.initialize(1024, new SecureRandom());
	KeyPair keyPair= keyPairGen.generateKeyPair();
	this.privateKey= (RSAPrivateKey) keyPair.getPrivate();
	this.publicKey= (RSAPublicKey) keyPair.getPublic();
	System.out.println(publicKey.getEncoded().length+"*****");
	System.out.println(AES.byteArrayToString(publicKey.getEncoded()));
}

下面就是加载公钥

/**
 * 从字节加载公钥
 * @param publicKeyStr 公钥数据字符串
 * @throws Exception 加载公钥时产生的异常
 */
public void loadPublicKey1(byte[] bytepublicKey) throws Exception{
	try {
		KeyFactory keyFactory= KeyFactory.getInstance("RSA");
		X509EncodedKeySpec keySpec= new X509EncodedKeySpec(bytepublicKey);
		this.publicKey= (RSAPublicKey) keyFactory.generatePublic(keySpec);
	} catch (NoSuchAlgorithmException e) {
		throw new Exception("无此算法");
	} catch (InvalidKeySpecException e) {
		throw new Exception("公钥非法");
	} catch (NullPointerException e) {
		throw new Exception("公钥数据为空");
	}
}
这里可以看到使用keyFactory.generatePublic加载keySpec,这里的keySpec是X509格式,如果你bytepublicKey没有162个字节的话,那么在keyFactory.generatePublic注定会报出“公钥非法”的错误。但是我得ukey生成的公钥只有128 bytes也就注定我无法使用X509格式。

-----------------------------------分割------------------------------------------

首先说Ukey:

Ukey采用

RSA_GenKey(&kpub, &kpri, RSA_1024+RSA_E_0x10001+RSA_noCRT);
1024位密钥,RSA算法,公钥类型10001 16进制,私钥类型不采用CRT。

加密出的数据:

01 02 03 04 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
加密后:

70 B2 86 5F 2E 1B C9 EC FC E1 40 30 0F 89 20 97 31 88 61 24 6B 42 9B 5D C4 78 FE D6 AA 1C 0C F6 24 59 F1 2F 73 41 53 C3 BB 15 AB C3 6C 8B 61 75 3E 27 06 4C E6 D2 BF B0 9C D5 AF 89 89 93 D0 9E FF EE 42 C1 36 B7 77 D9 6A 9D D8 74 20 31 FF 01 EB C5 CA D0 24 33 3E 9F 3B E9 28 6E C7 CE 51 A9 2F 40 DA DB 17 43 A7 52 39 8F E5 A4 57 AB 65 FC 93 22 89 47 DF 72 6A 34 83 6F 20 4A E7 53 68 15
再来说android:

/**
 * 加载字节公钥信息
 */
public void loadPublicKey(byte[] bytepublicKey) throws Exception{
	try {
		System.out.println(bytepublicKey.length+"*****");//DER
		KeyFactory keyFactory= KeyFactory.getInstance("RSA");
		RSAPublicKeySpec keySpec= new RSAPublicKeySpec(new BigInteger(
				bytepublicKey), new BigInteger("10001", 16));
		this.publicKey= (RSAPublicKey) keyFactory.generatePublic(keySpec);
	} catch (NoSuchAlgorithmException e) {
		throw new Exception("无此算法");
	}  catch (NullPointerException e) {
		throw new Exception("公钥数据为空");
	}
}
数据加密流程:

/**
 * 加密过程
 * @param publicKey 公钥
 * @param plainTextData 明文数据
 * @return
 * @throws Exception 加密过程中的异常信息
 */
public byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception{
	if(publicKey== null){
		throw new Exception("加密公钥为空, 请设置");
	}
	Cipher cipher= null;
	try {
		cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		
		byte[] output= cipher.doFinal(plainTextData);
		return output;
	} catch (NoSuchAlgorithmException e) {
		throw new Exception("无此加密算法");
	} catch (NoSuchPaddingException e) {
		e.printStackTrace();
		return null;
	}catch (InvalidKeyException e) {
		throw new Exception("加密公钥非法,请检查");
	} catch (IllegalBlockSizeException e) {
		throw new Exception("明文长度非法");
	} catch (BadPaddingException e) {
		throw new Exception("明文数据已损坏");
	}
}
下面贴一下加密前的数据:



加密后的数据:


这里可以核对一下和Ukey加密出来的数据是一样的。在android上的关键点就是

RSAPublicKeySpec keySpec= new RSAPublicKeySpec(new BigInteger(
				bytepublicKey), new BigInteger("10001", 16));
这里使用了RSAPublicKeySpec,公钥格式为10001 16进制,非常的关键。


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值