选择Java加密算法第3部分–公钥/私钥非对称加密
抽象
這是涵蓋Java加密算法的三部分博客系列的第3部分。 本系列介紹如何實現以下目標:
這第三篇文章詳細介紹了如何實現非對稱的RSA-4096公/私鑰加密。 讓我們開始吧。
免責聲明
這篇文章僅供參考。 在使用所提供的任何信息之前,請認真思考。 從中學到東西,但最終自己做出決定,風險自負。
要求
我使用以下主要技術完成了本文的所有工作。 您可能可以使用不同的技術或版本來做相同的事情,但不能保證。
- Java 1.8.0_152_x64
- NetBeans 8.2(內部版本201609300101)
- Maven 3.0.5(與NetBeans捆綁在一起)
下載
訪問我的GitHub頁面以查看我所有的開源項目。 這篇文章的代碼位于項目中: thoth-cryptography
非對稱加密
關于
非對稱算法基于兩個密鑰:公鑰和私鑰。 公鑰負責加密,私鑰負責解密。 公用密鑰可以自由分發。 使用公共密鑰,任何客戶端都可以加密一條消息,只有您(使用私有密鑰)可以解密該消息(非對稱算法,第3段)。
非對稱算法是Internet的主力軍。 像SSH,OpenPGP,SSL和TLS之類的協議依賴于非對稱算法(Rouse,2016,第2段)。 使用網絡瀏覽器進行在線銀行之類的工作的人都固有地知道非對稱算法的重要性。
截至目前,已完成的研究似乎表明,以下是最佳和最安全的公鑰/私鑰,非對稱加密算法(Sheth,2017年,“選擇正確的算法”,第2段):
RSA不是分組密碼,因此ECB模式沒有多大意義,但是,即使未在內部使用該模式,也需要ECB來使Java工作(Brightwell,2015年)。 OAEP提供了高度的隨機性和填充性。 讓我們看一個例子。
例
清單1是RsaTest.java單元測試。 這是以下內容的完整演示:
清單2顯示了RsaKeyPairProducer.java 。 這是一個幫助程序類,負責產生一個新的KeyPair 。 KeyPair對同時包含PublicKey和PrivateKey 。
清單3顯示了RsaPrivateKeyProducer.java 。 這是一個幫助程序類,負責從byte[]再現PrivateKey 。
清單4顯示了RsaPublicKeyProducer.java 。 這是一個幫助程序類,負責從byte[]復制PublicKey 。
清單5顯示了ByteArrayWriter.java ,清單6顯示了ByteArrayReader.java 。 這些是幫助程序類,負責將byte[]讀寫到文件中。 由您決定如何存儲密鑰的byte[] ,但需要將其安全地存儲在某個地方(文件,數據庫,git存儲庫等)。
清單7顯示了RsaEncrypter.java 。 這是一個負責加密的助手類。
最后,清單8顯示了RsaDecrypter.java 。 這是一個負責解密的助手類。
清單1 – RsaTest.java類
package org.thoth.crypto.asymmetric;import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.thoth.crypto.io.ByteArrayReader; import org.thoth.crypto.io.ByteArrayWriter;/**** @author Michael Remijan mjremijan@yahoo.com @mjremijan*/ public class RsaTest {static Path privateKeyFile;static Path publicKeyFile;@BeforeClasspublic static void beforeClass() throws Exception {// Store the PrivateKey and PublicKey bytes in the ./target// diretory. Do this so it will be ignore by source control.// We don't want this file committed.privateKeyFile= Paths.get("./target/RsaPrivate.key").toAbsolutePath();publicKeyFile= Paths.get("./target/RsaPublic.key").toAbsolutePath();// Create KeyPair for RSAKeyPair keyPair= new RsaKeyPairProducer().produce();// Store the PrivateKey bytes. This is what// you want to keep absolutely safe{ByteArrayWriter writer = new ByteArrayWriter(privateKeyFile);writer.write(keyPair.getPrivate().getEncoded());}// Store the PublicKey bytes. This you// can freely distribute so others can// encrypt messages which you can then// decrypt with the PrivateKey you keep safe.{ByteArrayWriter writer = new ByteArrayWriter(publicKeyFile);writer.write(keyPair.getPublic().getEncoded());}}@Testpublic void encrypt_and_decrypt() throws Exception {// setupPrivateKey privateKey= new RsaPrivateKeyProducer().produce(new ByteArrayReader(privateKeyFile).read());PublicKey publicKey= new RsaPublicKeyProducer().produce(new ByteArrayReader(publicKeyFile).read());RsaDecrypter decrypter= new RsaDecrypter(privateKey);RsaEncrypter encrypter= new RsaEncrypter(publicKey);String toEncrypt= "encrypt me";// runbyte[] encryptedBytes= encrypter.encrypt(toEncrypt);System.out.printf("Encrypted %s%n", new String(encryptedBytes,"UTF-8"));String decrypted= decrypter.decrypt(encryptedBytes);// assertAssert.assertEquals(toEncrypt, decrypted);}}清單2 – RsaKeyPairProducer.java類
package org.thoth.crypto.asymmetric;import java.security.KeyPair; import java.security.KeyPairGenerator;/**** @author Michael Remijan mjremijan@yahoo.com @mjremijan*/ public class RsaKeyPairProducer {/*** Generates a new RSA-4096 bit {@code KeyPair}.** @return {@code KeyPair}, never null* @throws RuntimeException All exceptions are caught* and re-thrown as {@code RuntimeException}*/public KeyPair produce() {KeyPairGenerator keyGen;try {keyGen = KeyPairGenerator.getInstance("RSA");//keyGen.initialize(3072);keyGen.initialize(4096);return keyGen.generateKeyPair();} catch (Exception ex) {throw new RuntimeException(ex);}} }清單3 – RsaPrivateKeyProducer.java類
package org.thoth.crypto.asymmetric;import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec;/**** @author Michael Remijan mjremijan@yahoo.com @mjremijan*/ public class RsaPrivateKeyProducer {/*** Regenerates a previous RSA {@code PrivateKey}.** @param encodedByteArrayForPrivateKey The bytes this method* will use to regenerate a previously created {@code PrivateKey}** @return {@code PrivateKey}, never null* @throws RuntimeException All exceptions are caught* and re-thrown as {@code RuntimeException}*/public PrivateKey produce(byte[] encodedByteArrayForPrivateKey) {try {PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(encodedByteArrayForPrivateKey));return privateKey;} catch (Exception ex) {throw new RuntimeException(ex);}} }清單4 – RsaPublicKeyProducer.java類
package org.thoth.crypto.asymmetric;import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec;/**** @author Michael Remijan mjremijan@yahoo.com @mjremijan*/ public class RsaPublicKeyProducer {/*** Regenerates a previous RSA {@code PublicKey}.** @param encodedByteArrayForPublicKey The bytes this method* will use to regenerate a previously created {@code PublicKey}** @return {@code PublicKey}, never null* @throws RuntimeException All exceptions are caught* and re-thrown as {@code RuntimeException}*/public PublicKey produce(byte[] encodedByteArrayForPublicKey) {try {PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(encodedByteArrayForPublicKey));return publicKey;} catch (Exception ex) {throw new RuntimeException(ex);}} }清單5 – ByteArrayWriter.java類
package org.thoth.crypto.io;import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path;/**** @author Michael Remijan mjremijan@yahoo.com @mjremijan*/ public class ByteArrayWriter {protected Path outputFile;private void initOutputFile(Path outputFile) {this.outputFile = outputFile;}private void initOutputDirectory() {Path outputDirectory = outputFile.getParent();if (!Files.exists(outputDirectory)) {try {Files.createDirectories(outputDirectory);} catch (IOException e) {throw new RuntimeException(e);}}}public ByteArrayWriter(Path outputFile) {initOutputFile(outputFile);initOutputDirectory();}public void write(byte[] bytesArrayToWrite) {try (OutputStream os= Files.newOutputStream(outputFile);PrintWriter writer= new PrintWriter(os);){for (int i=0; i<bytesArrayToWrite.length; i++) {if (i>0) {writer.println();}writer.print(bytesArrayToWrite[i]);}} catch (IOException ex) {throw new RuntimeException(ex);}} }清單6 – ByteArrayReader.java類
package org.thoth.crypto.io;import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.file.Path; import java.util.Scanner;/**** @author Michael Remijan mjremijan@yahoo.com @mjremijan*/ public class ByteArrayReader {protected Path inputFile;public ByteArrayReader(Path inputFile) {this.inputFile = inputFile;}public byte[] read() {try (Scanner scanner= new Scanner(inputFile);ByteArrayOutputStream baos= new ByteArrayOutputStream();){while (scanner.hasNext()) {baos.write(Byte.parseByte(scanner.nextLine()));}baos.flush();return baos.toByteArray();} catch (IOException ex) {throw new RuntimeException(ex);}} }清單7 – RsaEncrypter.java類
package org.thoth.crypto.asymmetric;import java.security.PublicKey; import javax.crypto.Cipher;/**** @author Michael Remijan mjremijan@yahoo.com @mjremijan*/ public class RsaEncrypter {protected RsaCipher cipher;public RsaEncrypter(PublicKey key) {this.cipher = new RsaCipher(Cipher.ENCRYPT_MODE, key);}public byte[] encrypt(String message) {try {return cipher.update(message.getBytes("UTF-8")).doFinal();} catch (Exception e) {throw new RuntimeException(e);}} }清單8 – RsaDecrypter.java類
package org.thoth.crypto.asymmetric;import java.security.PrivateKey; import javax.crypto.Cipher;/**** @author Michael Remijan mjremijan@yahoo.com @mjremijan*/ public class RsaDecrypter {protected RsaCipher cipher;public RsaDecrypter(PrivateKey key) {this.cipher = new RsaCipher(Cipher.DECRYPT_MODE, key);}public String decrypt(byte[] message) {try {return new String(cipher.update(message).doFinal(), "UTF-8");} catch (Exception e) {throw new RuntimeException(e);}}}摘要
加密并不容易。 簡單的示例將為您的應用程序帶來帶有安全漏洞的實現。 如果需要公用/專用密鑰,非對稱加密算法,請使用具有4096位密鑰的RSA / ECB / OAEPWithSHA–512AndMGF1Padding。
參考文獻
Sheth,M.(2017年4月18日)。 Java密碼學中的加密和解密。 從https://www.veracode.com/blog/research/encryption-and-decryption-java-cryptography檢索。
- 最佳算法,模式和填充
- 使用4096位密鑰
華盛頓州布萊特韋爾,雨披。 (2015年5月4日)。 ECB模式與RSA加密一起使用是否安全? 從https://crypto.stackexchange.com/questions/25420/is-ecb-mode-safe-to-use-with-rsa-encryption檢索。
- 歐洲央行不適用; Java不會在幕后使用它。
- RSA使用隨機性和填充來避免相同明文的ECB問題生成相同的密文
瑪麗蓮娜 (2016年11月29日)。 Java –非對稱密碼術示例。 從https://www.mkyong.com/java/java-asymmetric-cryptography-example/檢索。
- 將公用/專用密鑰寫入文件
- 從文件中讀取公鑰/私鑰
- 加密與解密
密鑰大小。 (2017年10月12日)。 維基百科。 取自https://en.wikipedia.org/wiki/Key_size 。
- 到2030年,2048位密鑰就足夠了
- 如果2030年以后仍需要安全性,則應使用3072位的RSA密鑰長度
用戶4982。 (2013年11月4日)。 IV如何與RSA加密關聯使用? 取自https://crypto.stackexchange.com/questions/11403/how-are-ivs-used-in-association-with-rsa-encryption 。
- IV值不適用于RSA
翻譯自: https://www.javacodegeeks.com/2017/12/choosing-java-cryptographic-algorithms-part-3-public-private-key-asymmetric-encryption.html
總結
以上是生活随笔為你收集整理的选择Java加密算法第3部分–公钥/私钥非对称加密的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多少人开会需要备案登报(多少人开会需要备
- 下一篇: 电脑怎么把显卡改成n卡(显卡n卡设置)