Java怎么使用rsa非对称加密法进行加密
这篇文章主要介绍了Java怎么使用rsa非对称加密法进行加密,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
公钥与私钥是成对的,一般的,我们认为的是公钥加密、私钥解密、私钥签名、公钥验证,有人说成私钥加密,公钥解密时不对的。
公钥与私钥的生成有多种方式,可以通过程序生成(下文具体实现),可以通过openssl工具:
#生成一个私钥,推荐使用1024位的秘钥,秘钥以pem格式保存到-out参数指定的文件中,采用PKCS1格式opensslgenrsa-outrsa.pem1024#生成与私钥对应的公钥,生成的是SubjectPublicKey,一般配合PKCS8格式私钥使用opensslrsa-inrsa.pem-pubout-outrsa.pub
RSA生成公钥与私钥一般有两种格式:PKCS1和PKCS8,上面的命令生成的秘钥是PKCS1格式的,而公钥是Subject Public Key,一般配合PKCS8格式私钥使用,所以就可能会涉及到PKCS1和PKCS8之间的转换:
#PKCS1格式私钥转换为PKCS8格式私钥,私钥直接输出到-out参数指定的文件中opensslpkcs8-topk8-informPEM-inrsa.pem-outformpem-nocrypt-outrsa_pkcs8.pem#PKCS8格式私钥转换为PKCS1格式私钥,私钥直接输出到-out参数指定的文件中opensslrsa-inrsa_pkcs8.pem-outrsa_pkcs1.pem#PKCS1格式公钥转换为PKCS8格式公钥,转换后的内容直接输出opensslrsa-pubin-inrsa.pub-RSAPublicKey_out#PKCS8格式公钥转换为PKCS1格式公钥,转换后的内容直接输出opensslrsa-RSAPublicKey_in-pubout-inrsa.pub
现实中,我们往往从pem、crt、pfx文件获取公私和私钥,crt、pfx的制作可以参考:简单的制作ssl证书,并在nginx和IIS中使用。
Java实现为简化说明介绍,这里我直接封装了一个工具类,因为要从pem、crt、pfx文件获取公私和私钥,因此引用了一个第三方包:BouncyCastle,可以直接在pom.xml中添加依赖:
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.68</version></dependency>
简单封装的RsaUtil.java:
importjava.io.FileInputStream;importjava.io.FileReader;importjava.io.FileWriter;importjava.math.BigInteger;importjava.security.KeyFactory;importjava.security.KeyPair;importjava.security.KeyPairGenerator;importjava.security.KeyStore;importjava.security.PrivateKey;importjava.security.PublicKey;importjava.security.SecureRandom;importjava.security.Security;importjava.security.Signature;importjava.security.cert.Certificate;importjava.security.cert.CertificateFactory;importjava.security.cert.X509Certificate;importjava.security.interfaces.RSAPrivateKey;importjava.security.interfaces.RSAPublicKey;importjava.security.spec.KeySpec;importjava.security.spec.PKCS8EncodedKeySpec;importjava.security.spec.RSAPrivateCrtKeySpec;importjava.security.spec.RSAPublicKeySpec;importjava.security.spec.X509EncodedKeySpec;importjava.util.Enumeration;importjavax.crypto.Cipher;importorg.bouncycastle.asn1.ASN1Integer;importorg.bouncycastle.asn1.ASN1Primitive;importorg.bouncycastle.asn1.DLSequence;importorg.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;importorg.bouncycastle.asn1.pkcs.PrivateKeyInfo;importorg.bouncycastle.asn1.x509.AlgorithmIdentifier;importorg.bouncycastle.asn1.x509.SubjectPublicKeyInfo;importorg.bouncycastle.jce.provider.BouncyCastleProvider;importorg.bouncycastle.util.io.pem.PemObject;importorg.bouncycastle.util.io.pem.PemReader;importorg.bouncycastle.util.io.pem.PemWriter;publicclassRsaUtil{static{Security.addProvider(newBouncyCastleProvider());}/***随机生成密钥对**@paramusePKCS8*是否采用PKCS8填充模式*/publicstaticObject[]generateRsaKey(booleanusePKCS8)throwsException{KeyPairGeneratorkeyPairGen=KeyPairGenerator.getInstance("RSA",BouncyCastleProvider.PROVIDER_NAME);//初始化keyPairGen.initialize(1024,newSecureRandom());//生成一个密钥对,保存在keyPair中KeyPairkeyPair=keyPairGen.generateKeyPair();RSAPrivateKeyprivateKey=(RSAPrivateKey)keyPair.getPrivate();//得到私钥RSAPublicKeypublicKey=(RSAPublicKey)keyPair.getPublic();//得到公钥//这两个公私钥是PKCS8格式的byte[]publicKeyBytes=publicKey.getEncoded();byte[]privateKeyBytes=privateKey.getEncoded();if(!usePKCS8){//将PSCK8格式公私钥转换为PKCS1格式publicKeyBytes=pkcs8ToPkcs1(false,publicKeyBytes);privateKeyBytes=pkcs8ToPkcs1(true,privateKeyBytes);}returnnewObject[]{publicKeyBytes,privateKeyBytes};}/***从Pem文件读取密钥对**@paramreader*输入流*@parampemFileName*pem文件*/publicstaticbyte[]readFromPem(StringpemFileName)throwsException{PemReaderpemReader=newPemReader(newFileReader(pemFileName));PemObjectpemObject=pemReader.readPemObject();byte[]publicKey=pemObject.getContent();pemReader.close();returnpublicKey;}/***从Pem文件读取密钥**@paramisPrivateKey*是否是私钥*@parambuffer*字节*@parampemFileName*pem文件*/publicstaticvoidwriteToPem(byte[]buffer,booleanisPrivateKey,StringpemFileName)throwsException{PemObjectpemObject=newPemObject(isPrivateKey?"RSAPRIVATEKEY":"RSAPUBLICKEY",buffer);FileWriterfileWriter=newFileWriter(pemFileName);PemWriterpemWriter=newPemWriter(fileWriter);pemWriter.writeObject(pemObject);pemWriter.close();}/***从crt文件读取公钥(pkcs8)**@paramcrtFileName*crt文件*@return公钥*/publicstaticbyte[]readPublicKeyFromCrt(StringcrtFileName)throwsException{CertificateFactorycf=CertificateFactory.getInstance("X.509");X509Certificatecert=(X509Certificate)cf.generateCertificate(newFileInputStream(crtFileName));PublicKeypublicKey=cert.getPublicKey();returnpublicKey.getEncoded();}/***从pfx文件读取秘钥对(pkcs8)**@parampfxFileName*pfx文件*@return秘钥对*/publicstaticObject[]readFromPfx(StringpfxFileName,Stringpassword)throwsException{KeyStorekeystore=KeyStore.getInstance("PKCS12");char[]passwordChars=null;if(password==null||password.equals("")){passwordChars=null;}else{passwordChars=password.toCharArray();}keystore.load(newFileInputStream(pfxFileName),passwordChars);Enumeration<String>enums=keystore.aliases();PrivateKeyprivateKey=null;Certificatecertificate=null;while(enums.hasMoreElements()){Stringalias=enums.nextElement();System.out.println(alias);if(keystore.isKeyEntry(alias)){privateKey=(PrivateKey)keystore.getKey(alias,passwordChars);certificate=keystore.getCertificate(alias);}if(privateKey!=null&&certificate!=null)break;}if(privateKey==null||certificate==null){thrownewException("failtoreadkeyfrompfx");}PublicKeypublicKey=certificate.getPublicKey();returnnewObject[]{publicKey.getEncoded(),privateKey.getEncoded()};}/***Pkcs8转Pkcs1**@paramisPrivateKey*是否是私钥转换*@parambuffer*Pkcs1秘钥*@returnPkcs8秘钥*@throwsException*加密过程中的异常信息*/publicstaticbyte[]pkcs8ToPkcs1(booleanisPrivateKey,byte[]buffer)throwsException{if(isPrivateKey){PrivateKeyInfoprivateKeyInfo=PrivateKeyInfo.getInstance(buffer);returnprivateKeyInfo.parsePrivateKey().toASN1Primitive().getEncoded();}else{SubjectPublicKeyInfosubjectPublicKeyInfo=SubjectPublicKeyInfo.getInstance(buffer);returnsubjectPublicKeyInfo.parsePublicKey().toASN1Primitive().getEncoded();}}/***Pkcs1转Pkcs8**@paramisPrivateKey*是否是私钥转换*@parambuffer*Pkcs1秘钥*@returnPkcs8秘钥*@throwsException*加密过程中的异常信息*/publicstaticbyte[]pkcs1ToPkcs8(booleanisPrivateKey,byte[]buffer)throwsException{AlgorithmIdentifieralgorithmIdentifier=newAlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption);ASN1Primitiveasn1Primitive=ASN1Primitive.fromByteArray(buffer);if(isPrivateKey){PrivateKeyInfoprivateKeyInfo=newPrivateKeyInfo(algorithmIdentifier,asn1Primitive);returnprivateKeyInfo.getEncoded();}else{SubjectPublicKeyInfosubjectPublicKeyInfo=newSubjectPublicKeyInfo(algorithmIdentifier,asn1Primitive);returnsubjectPublicKeyInfo.getEncoded();}}/***RSA公钥**@paramusePKCS8*是否采用PKCS8填充模式*@parampublicKey*公钥*@return公钥*@throwsException*加密过程中的异常信息*/publicstaticRSAPublicKeygeneratePublicKey(booleanusePKCS8,byte[]publicKey)throwsException{KeySpeckeySpec;if(usePKCS8){//PKCS8填充keySpec=newX509EncodedKeySpec(publicKey);}else{//PKCS1填充DLSequencesequence=(DLSequence)ASN1Primitive.fromByteArray(publicKey);BigIntegerv1=((ASN1Integer)sequence.getObjectAt(0)).getValue();BigIntegerv2=((ASN1Integer)sequence.getObjectAt(1)).getValue();keySpec=newRSAPublicKeySpec(v1,v2);}RSAPublicKeypubKey=(RSAPublicKey)KeyFactory.getInstance("RSA",BouncyCastleProvider.PROVIDER_NAME).generatePublic(keySpec);returnpubKey;}/***RSA私钥**@paramusePKCS8*是否采用PKCS8填充模式*@paramprivateKey*私钥*@return私钥*@throwsException*解密过程中的异常信息*/publicstaticRSAPrivateKeygeneratePrivateKey(booleanusePKCS8,byte[]privateKey)throwsException{KeySpeckeySpec;if(usePKCS8){//PKCS8填充keySpec=newPKCS8EncodedKeySpec(privateKey);}else{//PKCS1填充DLSequencesequence=(DLSequence)ASN1Primitive.fromByteArray(privateKey);//BigIntegerv1=((ASN1Integer)sequence.getObjectAt(0)).getValue();BigIntegerv2=((ASN1Integer)sequence.getObjectAt(1)).getValue();BigIntegerv3=((ASN1Integer)sequence.getObjectAt(2)).getValue();BigIntegerv4=((ASN1Integer)sequence.getObjectAt(3)).getValue();BigIntegerv5=((ASN1Integer)sequence.getObjectAt(4)).getValue();BigIntegerv6=((ASN1Integer)sequence.getObjectAt(5)).getValue();BigIntegerv7=((ASN1Integer)sequence.getObjectAt(6)).getValue();BigIntegerv8=((ASN1Integer)sequence.getObjectAt(7)).getValue();BigIntegerv9=((ASN1Integer)sequence.getObjectAt(8)).getValue();keySpec=newRSAPrivateCrtKeySpec(v2,v3,v4,v5,v6,v7,v8,v9);}RSAPrivateKeypriKey=(RSAPrivateKey)KeyFactory.getInstance("RSA",BouncyCastleProvider.PROVIDER_NAME).generatePrivate(keySpec);returnpriKey;}/***RSA公钥加密**@paramvalue*加密字符串*@parampublicKey*公钥*@return密文*@throwsException*加密过程中的异常信息*/publicstaticStringrsaEncrypt(Stringvalue,RSAPublicKeypublicKey)throwsException{if(value==null||value.length()==0)return"";//RSA加密Ciphercipher=Cipher.getInstance("RSA");cipher.init(Cipher.ENCRYPT_MODE,publicKey);byte[]buffer=cipher.doFinal(value.getBytes("utf-8"));//使用hex格式输出公钥StringBufferresult=newStringBuffer();for(inti=0;i<buffer.length;i++){result.append(String.format("%02x",buffer[i]));}returnresult.toString();}/***RSA私钥解密**@paramvalue*加密字符串*@paramprivateKey*私钥*@return明文*@throwsException*解密过程中的异常信息*/publicstaticStringrsaDecrypt(Stringvalue,RSAPrivateKeyprivateKey)throwsException{if(value==null||value.length()==0)return"";byte[]buffer=newbyte[value.length()/2];for(inti=0;i<buffer.length;i++){buffer[i]=(byte)Integer.parseInt(value.substring(i*2,i*2+2),16);}//RSA解密Ciphercipher=Cipher.getInstance("RSA");cipher.init(Cipher.DECRYPT_MODE,privateKey);buffer=cipher.doFinal(buffer);returnnewString(buffer,"utf-8");}/***RSA签名**@paramvalue*加密字符串*@paramprivateKey*私钥*@paramhalg*加密算法,如MD5,SHA1,SHA256,SHA384,SHA512等*@return签名*@throwsException*签名过程中的异常信息*/publicstaticStringsign(Stringvalue,RSAPrivateKeyprivateKey,Stringhalg)throwsException{Signatures=Signature.getInstance(halg.toUpperCase().endsWith("WithRSA")?halg:(halg+"WithRSA"));s.initSign(privateKey);s.update(value.getBytes("utf-8"));byte[]buffer=s.sign();//使用hex格式输出公钥StringBufferresult=newStringBuffer();for(inti=0;i<buffer.length;i++){result.append(String.format("%02x",buffer[i]));}returnresult.toString();}/***RSA签名验证**@paramvalue*加密字符串*@parampublicKey*公钥*@paramhalg*加密算法,如MD5,SHA1,SHA256,SHA384,SHA512等*@return签名合法则返回true,否则返回false*@throwsException*验证过程中的异常信息*/publicstaticbooleanverify(Stringvalue,RSAPublicKeypublicKey,Stringsignature,Stringhalg)throwsException{Signatures=Signature.getInstance(halg.toUpperCase().endsWith("WithRSA")?halg:(halg+"WithRSA"));s.initVerify(publicKey);s.update(value.getBytes("utf-8"));byte[]buffer=newbyte[signature.length()/2];for(inti=0;i<buffer.length;i++){buffer[i]=(byte)Integer.parseInt(signature.substring(i*2,i*2+2),16);}returns.verify(buffer);}}
生成公钥和私钥:
//生成公私钥Object[]rsaKey=RsaUtil.generateRsaKey(usePKCS8);//usePKCS8=true表示是否成PKCS8格式的公私秘钥,否则乘车PKCS1格式的公私秘钥byte[]publicKey=(byte[])rsaKey[0];byte[]privateKey=(byte[])rsaKey[1];
生成秘钥后,需要保存,一般保存到pem文件中:
//保存到pem文件,filePath是保存目录RsaUtil.writeToPem(publicKey,false,filePath+"rsa.pub");RsaUtil.writeToPem(privateKey,true,filePath+"rsa.pem");
可以保存到pem文件中,当然也可以从pem文件中读取了:
//从Pem文件读取公私钥,filePath是文件目录byte[]publicKey=RsaUtil.readFromPem(filePath+"rsa.pub");byte[]privateKey=RsaUtil.readFromPem(filePath+"rsa.pem");
还可以从crt证书中读取公钥,而crt文件不包含私钥,因此需要单独获取私钥:
//从crt文件读取公钥(crt文件中不包含私钥),filePath是文件目录byte[]publicKey=RsaUtil.readPublicKeyFromCrt(filePath+"demo.crt");byte[]privateKey=RsaUtil.readFromPem(filePath+"demo.key");
pfx文件中包含了公钥和私钥,可以很方便就读取到:
//从pfx文件读取公私钥,filePath是文件目录Object[]rsaKey=RsaUtil.readFromPfx(filePath+"demo.pfx","123456");byte[]publicKey=(byte[])rsaKey[0];byte[]privateKey=(byte[])rsaKey[1];
有时候我们还可能需要进行秘钥的转换:
//Pkcs8格式公钥转换为Pkcs1格式公钥publicKey=RsaUtil.pkcs8ToPkcs1(false,publicKey);//Pkcs8格式私钥转换为Pkcs1格式私钥privateKey=RsaUtil.pkcs8ToPkcs1(true,privateKey);//Pkcs1格式公钥转换为Pkcs8格式公钥publicKey=RsaUtil.pkcs1ToPkcs8(false,publicKey);//Pkcs1格式私钥转换为Pkcs8格式私钥privateKey=RsaUtil.pkcs1ToPkcs8(true,privateKey);
有了公钥和私钥,接下就就能实现加密、解密、签名、验证签名等操作了:
RSAPublicKeyrsaPublicKey=RsaUtil.generatePublicKey(usePKCS8,publicKey);RSAPrivateKeyrsaPrivateKey=RsaUtil.generatePrivateKey(usePKCS8,privateKey);StringencryptText=RsaUtil.rsaEncrypt(text,rsaPublicKey);System.out.printf("【%s】经过【RSA】加密后:%s\n",text,encryptText);StringdecryptText=RsaUtil.rsaDecrypt(encryptText,rsaPrivateKey);System.out.printf("【%s】经过【RSA】解密后:%s\n",encryptText,decryptText);Stringsignature=RsaUtil.sign(text,rsaPrivateKey,"MD5");System.out.printf("【%s】经过【RSA】签名后:%s\n",text,signature);booleanresult=RsaUtil.verify(text,rsaPublicKey,signature,"MD5");System.out.printf("【%s】的签名【%s】经过【RSA】验证后结果是:"+result,text,signature);
这里完整的demo代码:
importjava.security.interfaces.RSAPrivateKey;importjava.security.interfaces.RSAPublicKey;publicclassRsaMain{publicstaticvoidmain(String[]args){try{Stringtext="上山打老虎";booleanusePKCS8=true;//usePKCS8=true表示是否成PKCS8格式的公私秘钥,否则乘车PKCS1格式的公私秘钥StringfilePath=RsaUtil.class.getClassLoader().getResource("").getPath();System.out.printf("文件路径:%s\n",filePath);//存放pem,crt,pfx等文件的目录byte[]publicKey,privateKey;//公钥和私钥//生成公私钥Object[]rsaKey=RsaUtil.generateRsaKey(usePKCS8);//usePKCS8=true表示是否成PKCS8格式的公私秘钥,否则乘车PKCS1格式的公私秘钥publicKey=(byte[])rsaKey[0];privateKey=(byte[])rsaKey[1];//从Pem文件读取公私钥,filePath是文件目录//publicKey=RsaUtil.readFromPem(filePath+"rsa.pub");//privateKey=RsaUtil.readFromPem(filePath+"rsa.pem");//从pfx文件读取公私钥,filePath是文件目录//Object[]rsaKey=RsaUtil.readFromPfx(filePath+"demo.pfx",//"123456");//publicKey=(byte[])rsaKey[0];//privateKey=(byte[])rsaKey[1];//从crt文件读取公钥(crt文件中不包含私钥),filePath是文件目录//publicKey=RsaUtil.readPublicKeyFromCrt(filePath+"demo.crt");//privateKey=RsaUtil.readFromPem(filePath+"demo.key");//保存到pem文件,filePath是保存目录RsaUtil.writeToPem(publicKey,false,filePath+"rsa.pub");RsaUtil.writeToPem(privateKey,true,filePath+"rsa.pem");//Pkcs8格式公钥转换为Pkcs1格式公钥publicKey=RsaUtil.pkcs8ToPkcs1(false,publicKey);//Pkcs8格式私钥转换为Pkcs1格式私钥privateKey=RsaUtil.pkcs8ToPkcs1(true,privateKey);//Pkcs1格式公钥转换为Pkcs8格式公钥publicKey=RsaUtil.pkcs1ToPkcs8(false,publicKey);//Pkcs1格式私钥转换为Pkcs8格式私钥privateKey=RsaUtil.pkcs1ToPkcs8(true,privateKey);RSAPublicKeyrsaPublicKey=RsaUtil.generatePublicKey(usePKCS8,publicKey);RSAPrivateKeyrsaPrivateKey=RsaUtil.generatePrivateKey(usePKCS8,privateKey);StringencryptText=RsaUtil.rsaEncrypt(text,rsaPublicKey);System.out.printf("【%s】经过【RSA】加密后:%s\n",text,encryptText);StringdecryptText=RsaUtil.rsaDecrypt(encryptText,rsaPrivateKey);System.out.printf("【%s】经过【RSA】解密后:%s\n",encryptText,decryptText);Stringsignature=RsaUtil.sign(text,rsaPrivateKey,"MD5");System.out.printf("【%s】经过【RSA】签名后:%s\n",text,signature);booleanresult=RsaUtil.verify(text,rsaPublicKey,signature,"MD5");System.out.printf("【%s】的签名【%s】经过【RSA】验证后结果是:"+result,text,signature);}catch(Exceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}}}
感谢你能够认真阅读完这篇文章,希望小编分享的“Java怎么使用rsa非对称加密法进行加密”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。