Java中RSA加密解密的实现方法分析
本文实例讲述了Java中RSA加密解密的实现方法。分享给大家供大家参考,具体如下:
publicstaticvoidmain(String[]args)throwsException{ //TODOAuto-generatedmethodstub HashMapmap=RSAUtils.getKeys(); //生成公钥和私钥 RSAPublicKeypublicKey=(RSAPublicKey)map.get("public"); RSAPrivateKeyprivateKey=(RSAPrivateKey)map.get("private"); //模 Stringmodulus=publicKey.getModulus().toString(); //公钥指数 Stringpublic_exponent=publicKey.getPublicExponent().toString(); //私钥指数 Stringprivate_exponent=privateKey.getPrivateExponent().toString(); //明文 Stringming="123456789"; //使用模和指数生成公钥和私钥 RSAPublicKeypubKey=RSAUtils.getPublicKey(modulus,public_exponent); RSAPrivateKeypriKey=RSAUtils.getPrivateKey(modulus,private_exponent); //加密后的密文 Stringmi=RSAUtils.encryptByPublicKey(ming,pubKey); System.err.println(mi); //解密后的明文 ming=RSAUtils.decryptByPrivateKey(mi,priKey); System.err.println(ming); }
RSAUtils.Java
packageyyy.test.rsa; importjava.math.BigInteger; importjava.security.KeyFactory; importjava.security.KeyPair; importjava.security.KeyPairGenerator; importjava.security.NoSuchAlgorithmException; importjava.security.interfaces.RSAPrivateKey; importjava.security.interfaces.RSAPublicKey; importjava.security.spec.RSAPrivateKeySpec; importjava.security.spec.RSAPublicKeySpec; importjava.util.HashMap; importjavax.crypto.Cipher; publicclassRSAUtils{ /** *生成公钥和私钥 *@throwsNoSuchAlgorithmException * */ publicstaticHashMapgetKeys()throwsNoSuchAlgorithmException{ HashMap map=newHashMap (); KeyPairGeneratorkeyPairGen=KeyPairGenerator.getInstance("RSA"); keyPairGen.initialize(1024); KeyPairkeyPair=keyPairGen.generateKeyPair(); RSAPublicKeypublicKey=(RSAPublicKey)keyPair.getPublic(); RSAPrivateKeyprivateKey=(RSAPrivateKey)keyPair.getPrivate(); map.put("public",publicKey); map.put("private",privateKey); returnmap; } /** *使用模和指数生成RSA公钥 *注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA */None/NoPadding】 * *@parammodulus *模 *@paramexponent *指数 *@return */ publicstaticRSAPublicKeygetPublicKey(Stringmodulus,Stringexponent){ try{ BigIntegerb1=newBigInteger(modulus); BigIntegerb2=newBigInteger(exponent); KeyFactorykeyFactory=KeyFactory.getInstance("RSA"); RSAPublicKeySpeckeySpec=newRSAPublicKeySpec(b1,b2); return(RSAPublicKey)keyFactory.generatePublic(keySpec); }catch(Exceptione){ e.printStackTrace(); returnnull; } } /** *使用模和指数生成RSA私钥 *注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA */None/NoPadding】 * *@parammodulus *模 *@paramexponent *指数 *@return */ publicstaticRSAPrivateKeygetPrivateKey(Stringmodulus,Stringexponent){ try{ BigIntegerb1=newBigInteger(modulus); BigIntegerb2=newBigInteger(exponent); KeyFactorykeyFactory=KeyFactory.getInstance("RSA"); RSAPrivateKeySpeckeySpec=newRSAPrivateKeySpec(b1,b2); return(RSAPrivateKey)keyFactory.generatePrivate(keySpec); }catch(Exceptione){ e.printStackTrace(); returnnull; } } /** *公钥加密 * *@paramdata *@parampublicKey *@return *@throwsException */ publicstaticStringencryptByPublicKey(Stringdata,RSAPublicKeypublicKey) throwsException{ Ciphercipher=Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE,publicKey); //模长 intkey_len=publicKey.getModulus().bitLength()/8; //加密数据长度<=模长-11 String[]datas=splitString(data,key_len-11); Stringmi=""; //如果明文长度大于模长-11则要分组加密 for(Strings:datas){ mi+=bcd2Str(cipher.doFinal(s.getBytes())); } returnmi; } /** *私钥解密 * *@paramdata *@paramprivateKey *@return *@throwsException */ publicstaticStringdecryptByPrivateKey(Stringdata,RSAPrivateKeyprivateKey) throwsException{ Ciphercipher=Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE,privateKey); //模长 intkey_len=privateKey.getModulus().bitLength()/8; byte[]bytes=data.getBytes(); byte[]bcd=ASCII_To_BCD(bytes,bytes.length); System.err.println(bcd.length); //如果密文长度大于模长则要分组解密 Stringming=""; byte[][]arrays=splitArray(bcd,key_len); for(byte[]arr:arrays){ ming+=newString(cipher.doFinal(arr)); } returnming; } /** *ASCII码转BCD码 * */ publicstaticbyte[]ASCII_To_BCD(byte[]ascii,intasc_len){ byte[]bcd=newbyte[asc_len/2]; intj=0; for(inti=0;i<(asc_len+1)/2;i++){ bcd[i]=asc_to_bcd(ascii[j++]); bcd[i]=(byte)(((j>=asc_len)?0x00:asc_to_bcd(ascii[j++]))+(bcd[i]<<4)); } returnbcd; } publicstaticbyteasc_to_bcd(byteasc){ bytebcd; if((asc>='0')&&(asc<='9')) bcd=(byte)(asc-'0'); elseif((asc>='A')&&(asc<='F')) bcd=(byte)(asc-'A'+10); elseif((asc>='a')&&(asc<='f')) bcd=(byte)(asc-'a'+10); else bcd=(byte)(asc-48); returnbcd; } /** *BCD转字符串 */ publicstaticStringbcd2Str(byte[]bytes){ chartemp[]=newchar[bytes.length*2],val; for(inti=0;i >4)&0x0f); temp[i*2]=(char)(val>9?val+'A'-10:val+'0'); val=(char)(bytes[i]&0x0f); temp[i*2+1]=(char)(val>9?val+'A'-10:val+'0'); } returnnewString(temp); } /** *拆分字符串 */ publicstaticString[]splitString(Stringstring,intlen){ intx=string.length()/len; inty=string.length()%len; intz=0; if(y!=0){ z=1; } String[]strings=newString[x+z]; Stringstr=""; for(inti=0;i java
Ciphercipher=Cipher.getInstance("RSA/ECB/PKCS1Padding");android
Ciphercipher=Cipher.getInstance("RSA/ECB/NoPadding");参考:
http://stackoverflow.com/questions/6069369/rsa-encryption-difference-between-java-and-android
http://stackoverflow.com/questions/2956647/rsa-encrypt-with-base64-encoded-public-key-in-android补充:关于RSA算法密钥长度/密文长度/明文长度
1.密钥长度
rsa算法初始化的时候一般要填入密钥长度,在96-1024bits间
(1)为啥下限是96bits(12bytes)?因为加密1byte的明文,需要至少1+11=12bytes的密钥(不懂?看下面的明文长度),低于下限96bits时,一个byte都加密不了,当然没意义啦
(2)为啥上限是1024(128bytes)?这是算法本身决定的...当然如果某天网上出现了支持2048bits长的密钥的rsa算法时,你当我废话吧2.明文长度
明文长度(bytes)<=密钥长度(bytes)-11.这样的话,对于上限密钥长度1024bits能加密的明文上限就是117bytes了.
这个规定很狗血,所以就出现了分片加密,网上很流行这个版本.很简单,如果明文长度大于那个最大明文长度了,我就分片吧,保证每片都别超过那个值就是了.
片数=(明文长度(bytes)/(密钥长度(bytes)-11))的整数部分+1,就是不满一片的按一片算3.密文长度
对,就是这个充满了谣言,都说密文长度为密钥长度的一半,经俺验证,密文长度等于密钥长度.当然这是不分片情况下的.
分片后,密文长度=密钥长度*片数例如96bits的密钥,明文4bytes
每片明文长度=96/8-11=1byte,片数=4,密文长度=96/8*4=48bytes又例如128bits的密钥,明文8bytes
每片明文长度=128/8-11=5bytes,片数=8/5取整+1=2,密文长度=128/8*2=32注意,对于指定长度的明文,其密文长度与密钥长度非正比关系.如4bytes的明文,在最短密钥96bites是,密文长度48bytes,128bits米密钥时,密文长度为16bytes,1024bits密钥时,密文长度128bytes.
因为分片越多,密文长度显然会变大,所以有人说,那就一直用1024bits的密钥吧...拜托,现在的机器算1024bits的密钥还是要点时间滴,别以为你的cpu很牛逼...那么选个什么值比较合适呢?个人认为是600bits,因为我们对于一个字符串的加密,一般不是直接加密,而是将字符串hash后,对hash值加密.现在的hash值一般都是4bytes,很少有8bytes,几十年内应该也不会超过64bytes.那就用64bytes算吧,密钥长度就是(64+11)*8=600bits了.用开源rsa算法的时候,还要注意,那个年代的人把long当4bytes用,如今放在64位的机器上,就会死循环啊多悲催....因为有个循环里让一个4bytes做递减....64位机上long是8bytes,这个循环进去后个把小时都出不来....所以要注意下哦....同理对于所有年代久远的开源库都得注意下...
PS:关于加密解密感兴趣的朋友还可以参考本站在线工具:
文字在线加密解密工具(包含AES、DES、RC4等):
http://tools.jb51.net/password/txt_encodeMD5在线加密工具:
http://tools.jb51.net/password/CreateMD5Password在线散列/哈希算法加密工具:
http://tools.jb51.net/password/hash_encrypt在线MD5/hash/SHA-1/SHA-2/SHA-256/SHA-512/SHA-3/RIPEMD-160加密工具:
http://tools.jb51.net/password/hash_md5_sha在线sha1/sha224/sha256/sha384/sha512加密工具:
http://tools.jb51.net/password/sha_encode更多关于java相关内容感兴趣的读者可查看本站专题:《Java数学运算技巧总结》、《Java数据结构与算法教程》、《Java字符与字符串操作技巧总结》、《java日期与时间操作技巧汇总》、《Java操作DOM节点技巧总结》和《Java缓存操作技巧汇总》
希望本文所述对大家java程序设计有所帮助。