一、什么是RSA加密算法:
RSA加密算法是一种非对称加密算法,所谓非对称,就是指该算法加密和解密使用不同的密钥,即使用加密密钥进行加密、解密密钥进行解密。在RAS算法中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,由于无法计算出大数n的欧拉函数phi(N),所以不能根据PK计算出SK。
也就是说,对极大整数做因数分解的难度决定了RSA算法的可靠性。理论上,只要其钥匙的长度n足够长,用RSA加密的信息实际上是不能被解破的。
RSA算法通常是先生成一对RSA密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位(对标文章结尾补充说明)。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要。
二、RSA加密方式
RSA加密是对明文的E次方后除以N后求余数的过程。所以,只要知道E和N任何人都可以进行RSA加密了,所以说E、N是RSA加密的密钥,也就是说E和N的组合就是公钥,我们用(E,N)来表示公钥:
密文=明文EmodN密文=明文EmodN
三、RSA解密过程
密文进行D次方后除以N的余数就是明文,这就是RSA解密过程。知道D和N就能进行解密密文了,所以D和N的组合就是私钥:
明文=密文DmodN明文=密文DmodN
四、进行实践
1、确定加密算法
// 加密算法privatefinalstaticStringALGORITHM_RSA="RSA";
2、生成公钥私钥密钥对
//生成公钥,私钥的密钥对publicstaticList<String>getRSAKeyString(intmodulus) throwsNoSuchAlgorithmException{ List<String>keyList=newArrayList<>(2); //密钥对生成,生成规范-RSA算法KeyPairGeneratorkeyPairGen=KeyPairGenerator.getInstance(ALGORITHM_RSA); //初始化模长keyPairGen.initialize(modulus); //生成密钥对KeyPairkeyPair=keyPairGen.generateKeyPair(); StringpublicKey=Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()); StringprivateKey=Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()); keyList.add(publicKey); keyList.add(privateKey); returnkeyList; } // Java中RSAPublicKeySpec、X509EncodedKeySpec支持生成RSA公钥// 此处使用X509EncodedKeySpec生成publicstaticRSAPublicKeygetPublicKey(StringpublicKey) throwsException { KeyFactorykeyFactory=KeyFactory.getInstance(ALGORITHM_RSA); byte[] keyBytes=Base64.getDecoder().decode(publicKey); X509EncodedKeySpecspec=newX509EncodedKeySpec(keyBytes); return (RSAPublicKey) keyFactory.generatePublic(spec); } // Java中只有RSAPrivateKeySpec、PKCS8EncodedKeySpec支持生成RSA私钥// 此处使用PKCS8EncodedKeySpec生成publicstaticRSAPrivateKeygetPrivateKey(StringprivateKey) throwsException { KeyFactorykeyFactory=KeyFactory.getInstance(ALGORITHM_RSA); byte[] keyBytes=Base64.getDecoder().decode(privateKey); PKCS8EncodedKeySpecspec=newPKCS8EncodedKeySpec(keyBytes); return (RSAPrivateKey) keyFactory.generatePrivate(spec); }
3、编写公钥加密步骤
//公钥加密publicstaticStringencryptByPublicKey(Stringdata, RSAPublicKeypublicKey)throwsException { Ciphercipher=Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, publicKey); // 模长n转换成字节数intmodulusSize=publicKey.getModulus().bitLength() /8; // PKCS Padding长度为11字节,所以实际要加密的数据不能要 - 11byteintmaxSingleSize=modulusSize-11; // 切分字节数组,每段不大于 maxSingleSizebyte[][] dataArray=splitArray(data.getBytes(), maxSingleSize); ByteArrayOutputStreamout=newByteArrayOutputStream(); // 分组加密,并将加密后的内容写入输出字节流for (byte[] s : dataArray) { out.write(cipher.doFinal(s)); } // 使用Base64将字节数组转换String类型returnBase64.getEncoder().encodeToString(out.toByteArray()); }
4、编写私钥解密过程
//私钥解密publicstaticStringdecryptByPrivateKey(Stringdata, RSAPrivateKeyprivateKey) throwsException { Ciphercipher=Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.DECRYPT_MODE, privateKey); // RSA加密算法的模长 nintmodulusSize=privateKey.getModulus().bitLength() /8; byte[] dataBytes=data.getBytes(); // 之前加密的时候做了转码,此处需要使用Base64进行解码byte[] decodeData=Base64.getDecoder().decode(dataBytes); // 切分字节数组,使每段不大于modulusSizebyte[][] splitArrays=splitArray(decodeData, modulusSize); ByteArrayOutputStreamout=newByteArrayOutputStream(); for(byte[] arr : splitArrays){ out.write(cipher.doFinal(arr)); } returnnewString(out.toByteArray()); }
5、切分数组工具方法
//切分数组privatestaticbyte[][] splitArray(byte[] data,intlen){ intdataLen=data.length; if (dataLen<=len) { returnnewbyte[][]{data}; } byte[][] result=newbyte[(dataLen-1)/len+1][]; intresultLen=result.length; for (inti=0; i<resultLen; i++) { if (i==resultLen-1) { intslen=dataLen-len*i; byte[] single=newbyte[slen]; System.arraycopy(data, len*i, single, 0, slen); result[i] =single; break; } byte[] single=newbyte[len]; System.arraycopy(data, len*i, single, 0, len); result[i] =single; } returnresult; }
6、主方法
publicstaticvoidmain(String[] args) throwsException { Stringmessage="红色基因是一种革命精神的传承,鼓舞着一代又一代中华儿女为了实现中华民族的伟大复兴的中国梦而坚强自立、坚持梦想、勇往直前!"; // 使用字符串生成公钥、私钥完成加解密List<String>keyStringList=AsyEnc.getRSAKeyString(1024); StringpukString=keyStringList.get(0); StringprkString=keyStringList.get(1); System.out.println("公钥:"+pukString); System.out.println("私钥:"+prkString); // 生成公钥RSAPublicKeypuk=AsyEnc.getPublicKey(pukString); // 生成私钥RSAPrivateKeyprk=AsyEnc.getPrivateKey(prkString); // 加密messageStringencryptedMsg=AsyEnc.encryptByPublicKey(message, puk); StringdecryptedMsg=AsyEnc.decryptByPrivateKey(encryptedMsg, prk); System.out.println("加密后 message : "+encryptedMsg); System.out.println("解密后 message : "+decryptedMsg); }
7、测试执行
8、补充说明
主方法中 :getRSAKeyString(1024)为自设定mod值,也为下图中RAS密钥长度