对称密钥加密算法 对称轮数

抽象

这是涵盖Java加密算法的三部分博客系列的第2部分。 该系列涵盖如何实现以下功能:

  1. 使用SHA–512散列
  2. AES–256
  3. RSA–4096

这第二篇文章详细介绍了如何实现单密钥对称AES-256加密。 让我们开始吧。

免责声明

这篇文章仅供参考。 在使用所提供的任何信息之前,请认真思考。 从中学到东西,但最终自己做出决定,风险自负。

要求

我使用以下主要技术完成了本文的所有工作。 您可能可以使用不同的技术或版本来做相同的事情,但不能保证。

  • Java 1.8.0_152_x64
  • Java密码术扩展(JCE)的无限强度
  • NetBeans 8.2(内部版本201609300101)
  • Maven 3.0.5(与NetBeans捆绑在一起)

下载

访问我的GitHub页面以查看我所有的开源项目。 这篇文章的代码位于项目中: thoth-cryptography

对称加密

关于

对称加密算法基于单个密钥。 此密钥用于加密和解密。 因此,对称算法仅应在严格控制密钥的地方使用。

对称算法通常用于安全环境中的数据加密和解密。 一个很好的例子是确保微服务通信的安全。 如果OAuth-2 / JWT体系结构超出范围,则API网关可以使用对称算法的单密钥来加密令牌。 然后将此令牌传递给其他微服务。 其他微服务使用相同的密钥来解密令牌。 另一个很好的例子是电子邮件中嵌入的超链接。 电子邮件中的超链接包含一个编码的令牌,当单击该超链接时,该令牌允许自动登录请求处理。 此令牌是由对称算法生成的高度加密的值,因此只能在应用程序服务器上解码。 当然,任何时候都需要保护任何类型的密码或凭证,使用对称算法对它们进行加密,然后可以使用相同的密钥对字节进行解密。

截止目前的研究似乎表明,以下是最佳和最安全的单密钥,对称加密算法(Sheth,2017年,“选择正确的算法”,第2段):

  1. 算法: AES
  2. 模式: GCM
  3. 填充: PKCS5Padding
  4. 密钥大小: 256位
  5. IV大小: 96位

AES–256使用256位密钥, 需要安装Java密码学扩展(JCE)无限强度软件包。 让我们看一个例子。

注意: 256位密钥需要Java密码术扩展(JCE)无限强度软件包。 如果未安装,则最大为128位密钥。

如果尚未安装,请下载并安装Java Cryptography Extension(JCE)无限强度软件包。 需要使用256位密钥。 否则,必须将以下示例更新为使用128位密钥。

清单1是AesTest.java单元测试。 这是以下内容的完整演示:

  1. 生成并存储AES 256位密钥
  2. AES加密
  3. AES解密

清单2显示了AesSecretKeyProducer.java 。 这是一个帮助程序类,负责产生一个新密钥或从byte[]复制一个现有密钥。

清单3显示了ByteArrayWriter.java ,清单4显示了ByteArrayReader.java 。 这些是负责将byte[]写入文件的助手类。 由您决定如何存储密钥的byte[] ,但需要将其安全地存储在某个地方(文件,数据库,git存储库等)。

最后,清单5显示了Aes.java 。 这是一个帮助程序类,负责加密和解密。

清单1 – AesTest.java类

package org.thoth.crypto.symmetric;import java.io.ByteArrayOutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import javax.crypto.SecretKey;
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 AesTest {static Path secretKeyFile;@BeforeClasspublic static void beforeClass() throws Exception {// Store the SecretKey bytes in the ./target diretory. Do// this so it will be ignore by source control.  We don't// want this file committed.secretKeyFile= Paths.get("./target/Aes256.key").toAbsolutePath();// Generate a SecretKey for the testSecretKey secretKey= new AesSecretKeyProducer().produce();// Store the byte[] of the SecretKey.  This is the// "private key file" you want to keep safe.ByteArrayWriter writer = new ByteArrayWriter(secretKeyFile);writer.write(secretKey.getEncoded());}@Testpublic void encrypt_and_decrypt_using_same_Aes256_instance() {// setupSecretKey secretKey= new AesSecretKeyProducer().produce(new ByteArrayReader(secretKeyFile).read());Aes aes= new Aes(secretKey);String toEncrypt= "encrypt me";// runbyte[] encryptedBytes= aes.encrypt(toEncrypt, Optional.empty());String decrypted= aes.decrypt(encryptedBytes, Optional.empty());// assertAssert.assertEquals(toEncrypt, decrypted);}public void encrypt_and_decrypt_with_aad_using_same_Aes256_instance() {// setupSecretKey secretKey= new AesSecretKeyProducer().produce(new ByteArrayReader(secretKeyFile).read());Aes aes= new Aes(secretKey);String toEncrypt= "encrypt me aad";// runbyte[] encryptedBytes= aes.encrypt(toEncrypt, Optional.of("JUnit AAD"));String decrypted= aes.decrypt(encryptedBytes, Optional.of("JUnit AAD"));// assertAssert.assertEquals(toEncrypt, decrypted);}@Testpublic void encrypt_and_decrypt_using_different_Aes256_instance()throws Exception {// setupSecretKey secretKey= new AesSecretKeyProducer().produce(new ByteArrayReader(secretKeyFile).read());Aes aesForEncrypt= new Aes(secretKey);Aes aesForDecrypt= new Aes(secretKey);String toEncrypt= "encrypt me";// runbyte[] encryptedBytes= aesForEncrypt.encrypt(toEncrypt, Optional.empty());ByteArrayOutputStream baos= new ByteArrayOutputStream();baos.write(encryptedBytes);String decrypted= aesForDecrypt.decrypt(baos.toByteArray(), Optional.empty());// assertAssert.assertEquals(toEncrypt, decrypted);}
}

清单2 – AesSecretKeyProducer.java类

package org.thoth.crypto.symmetric;import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;/**** @author Michael Remijan mjremijan@yahoo.com @mjremijan*/
public class AesSecretKeyProducer {/*** Generates a new AES-256 bit {@code SecretKey}.** @return {@code SecretKey}, never null* @throws RuntimeException All exceptions are caught and re-thrown as {@code RuntimeException}*/public SecretKey produce() {KeyGenerator keyGen;try {keyGen = KeyGenerator.getInstance("AES");keyGen.init(256);SecretKey secretKey = keyGen.generateKey();return secretKey;} catch (Exception ex) {throw new RuntimeException(ex);}}/*** Generates an AES-256 bit {@code SecretKey}.** @param encodedByteArray The bytes this method will use to regenerate a previously created {@code SecretKey}** @return {@code SecretKey}, never null* @throws RuntimeException All exceptions are caught and re-thrown as {@code RuntimeException}*/public SecretKey produce(byte [] encodedByteArray) {try {return new SecretKeySpec(encodedByteArray, "AES");} catch (Exception ex) {throw new RuntimeException(ex);}}
}

清单3 – 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);}}
}

清单4 – 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);}}
}

清单5 – Aes.java类

package org.thoth.crypto.symmetric;import java.security.SecureRandom;
import java.util.Optional;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;/**** @author Michael Remijan mjremijan@yahoo.com @mjremijan*/
public class Aes {// If you don't have the Java Cryptography Extension// (JCE) Unlimited Strength packaged installed, use// a 128 bit KEY_SIZE.public static int KEY_SIZE = 256;public static int IV_SIZE = 12; // 12bytes * 8 = 96bitspublic static int TAG_BIT_SIZE = 128;public static String ALGORITHM_NAME = "AES";public static String MODE_OF_OPERATION = "GCM";public static String PADDING_SCHEME = "PKCS5Padding";protected SecretKey secretKey;protected SecureRandom secureRandom;public Aes(SecretKey secretKey) {this.secretKey = secretKey;this.secureRandom = new SecureRandom();}public byte[] encrypt(String message, Optional<String> aad) {try {// Transformation specifies algortihm, mode of operation and paddingCipher c = Cipher.getInstance(String.format("%s/%s/%s",ALGORITHM_NAME,MODE_OF_OPERATION,PADDING_SCHEME));// Generate IVbyte iv[] = new byte[IV_SIZE];secureRandom.nextBytes(iv); // SecureRandom initialized using self-seeding// Initialize GCM ParametersGCMParameterSpec spec = new GCMParameterSpec(TAG_BIT_SIZE, iv);// Init for encryptionc.init(Cipher.ENCRYPT_MODE, secretKey, spec, secureRandom);// Add AAD tag data if presentaad.ifPresent(t -> {try {c.updateAAD(t.getBytes("UTF-8"));} catch (Exception e) {throw new RuntimeException(e);}});// Add message to encryptc.update(message.getBytes("UTF-8"));// Encryptbyte[] encryptedBytes= c.doFinal();// Concatinate IV and encrypted bytes.  The IV is needed later// in order to to decrypt.  The IV value does not need to be// kept secret, so it's OK to encode it in the return value//// Create a new byte[] the combined length of IV and encryptedBytesbyte[] ivPlusEncryptedBytes = new byte[iv.length + encryptedBytes.length];// Copy IV bytes into the new arraySystem.arraycopy(iv, 0, ivPlusEncryptedBytes, 0, iv.length);// Copy encryptedBytes into the new arraySystem.arraycopy(encryptedBytes, 0, ivPlusEncryptedBytes, iv.length, encryptedBytes.length);// Returnreturn ivPlusEncryptedBytes;} catch (Exception e) {throw new RuntimeException(e);}}public String decrypt(byte[] ivPlusEncryptedBytes, Optional<String> aad) {try {// Get IVbyte iv[] = new byte[IV_SIZE];System.arraycopy(ivPlusEncryptedBytes, 0, iv, 0, IV_SIZE);// Initialize GCM ParametersGCMParameterSpec spec = new GCMParameterSpec(TAG_BIT_SIZE, iv);// Transformation specifies algortihm, mode of operation and paddingCipher c = Cipher.getInstance(String.format("%s/%s/%s",ALGORITHM_NAME,MODE_OF_OPERATION,PADDING_SCHEME));// Get encrypted bytesbyte [] encryptedBytes = new byte[ivPlusEncryptedBytes.length - IV_SIZE];System.arraycopy(ivPlusEncryptedBytes, IV_SIZE, encryptedBytes, 0, encryptedBytes.length);// Init for decryptionc.init(Cipher.DECRYPT_MODE, secretKey, spec, secureRandom);// Add AAD tag data if presentaad.ifPresent(t -> {try {c.updateAAD(t.getBytes("UTF-8"));} catch (Exception e) {throw new RuntimeException(e);}});// Add message to decryptc.update(encryptedBytes);// Decryptbyte[] decryptedBytes= c.doFinal();// Returnreturn new String(decryptedBytes, "UTF-8");} catch (Exception e) {throw new RuntimeException(e);}}
}

摘要

加密并不容易。 简单的示例将为您的应用程序带来带有安全漏洞的实现。 如果您需要单密钥对称加密算法,请使用具有256位密钥和96位IV的密码AES / GCM / PKCS5Padding。

参考资料

  • Java密码术扩展(JCE)无限强度。 (nd)。 检索自http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html 。
  • Sheth,M.(2017年4月18日)。 Java密码学中的加密和解密。 从https://www.veracode.com/blog/research/encryption-and-decryption-java-cryptography检索。
  • cpast [表示GCM IV是96位,即96/8 = 12字节]。 (2015年6月4日)。 使用AES–256加密时,我可以使用256位IV [Web日志注释]。 从https://security.stackexchange.com/questions/90848/encrypting-using-aes-256-can-i-use-256-bits-iv检索
  • Bodewes [强烈建议将GCM IV设置为12个字节(12 * 8 = 96),但可以是任意大小。 其他尺寸将需要其他计算],M。(2015年7月7日)。 密文和标签大小以及在GCM模式下使用AES进行IV传输[Web日志注释]。 从https://crypto.stackexchange.com/questions/26783/ciphertext-and-tag-size-and-iv-transmission-with-aes-in-gcm-mode检索。
  • Figlesquidge。 (2013年10月18日)。 “密码”和“操作模式”之间有什么区别? [网络日志评论]。 从https://crypto.stackexchange.com/questions/11132/what-is-the-difference-between-a-cipher-and-a-mode-of-operation检索。
  • Toust,S.(2013年2月4日)。 为什么对称和非对称加密之间的建议密钥大小会有很大差异? 取自https://crypto.stackexchange.com/questions/6236/why-does-the-recommended-key-size-between-symmetric-and-asymmetric-encryption-di 。
  • 卡罗宁(I.)(2012年10月5日)。 密钥,IV和随机数之间的主要区别是什么? 从https://crypto.stackexchange.com/questions/3965/what-is-the-main-difference-between-a-key-an-iv-and-a-nonce检索。
  • 分组密码操作模式。 (2017年11月6日)。 维基百科。 取自https://zh.wikipedia.org/wiki/Block_cipher_mode_of_operation#Initialization_vector_.28IV.29

翻译自: https://www.javacodegeeks.com/2017/12/choosing-java-cryptographic-algorithms-part-2-single-key-symmetric-encryption.html

对称密钥加密算法 对称轮数

对称密钥加密算法 对称轮数_选择Java加密算法第2部分–单密钥对称加密相关推荐

  1. 非对称加密 公钥私钥_选择Java加密算法第3部分–公钥/私钥非对称加密

    非对称加密 公钥私钥 抽象 这是涵盖Java加密算法的三部分博客系列的第3部分. 该系列涵盖如何实现以下功能: 使用SHA–512散列 使用AES–256的单密钥对称加密 RSA–4096 这第三篇文 ...

  2. 选择Java加密算法第2部分–单密钥对称加密

    抽象 这是涵盖Java加密算法的三部分博客系列的第2部分. 本系列介绍如何实现以下目标: 使用SHA–512散列 AES–256 RSA–4096 这第二篇文章详细介绍了如何实现单密钥对称AES-25 ...

  3. java 哈希算法_选择Java密码算法第1部分-哈希

    java 哈希算法 抽象 这是涵盖Java加密算法的三部分博客系列文章的第1部分. 该系列涵盖如何实现以下功能: 使用SHA–512散列 使用AES–256的单密钥对称加密 使用RSA–4096的公钥 ...

  4. 选择Java加密算法第3部分–公钥/私钥非对称加密

    抽象 这是涵盖Java加密算法的三部分博客系列的第3部分. 本系列介绍如何实现以下目标: 使用SHA–512散列 使用AES–256的单密钥对称加密 RSA–4096 这第三篇文章详细介绍了如何实现非 ...

  5. aes子密钥生成c语言_一种基于流密码算法的子密钥生成方法与流程

    本发明涉及一种用于分组加解密算法的子密钥的生成方法. 背景技术: 随着信息技术的发展,信息安全性的问题却愈来愈显得突出,保证信息安全的一个重要技术就是密码学.密码学在信息安全技术中扮演着基础的角色,是 ...

  6. java 向量存储_关于java:使用AES-256和初始化向量进行加密

    我有一个关于在AES加密中使用初始化向量的问题.我正在引用以下文章/文章以将加密构建到我的程序中: [1]Java 256位AES密码加密[2]http://gmailassistant.source ...

  7. java读取文本单词_使用Java计算文本文件中的单词数

    我们可以使用Java的BufferedReader类读取文件中的单词,然后根据空格字符拆分读取的数据.请参阅以下示例: 示例 考虑类路径中的以下文本文件. test.txtThis is Line 1 ...

  8. java加密文件夹_使用java.util.zip压缩文件夹,支持加密,增加描述

    导读热词 下面是编程之家 jb51.cc 通过网络收集整理的代码片段. 编程之家小编现在分享给大家,也给大家做个参考. import java.io.File; import java.io.File ...

  9. 密钥生成并配置_如何在 CentOS 8 上设置 SSH 密钥

    本文最先发布在: 如何在 CentOS 8 上设置 SSH 密钥​www.itcoder.tech 安全 Shell (SSH) 是一个被设计用来在客户端和服务器之间进行安全连接的加密网络协议. 最流 ...

最新文章

  1. 【Python】函数的可变可选参数传递及返回值
  2. linux 系统lv扩展_Linux增加LV(逻辑卷)容量
  3. runtime相关知识
  4. 8.8-8.10 usaco
  5. 详解python3如何调用c语言代码
  6. javascript --- event loop
  7. java 客户化排序_第八部分_客户化JSP标签
  8. ibatis 数据库获取不到 java_如何拦截ibatis中所有的执行sql,并记录进数据库
  9. numpy中矩阵的转置_NumPy矩阵transpose()-Python中数组的转置
  10. 2 什么样的顾客会选择离开
  11. vs2015运行编译器遇到堆空间不足问题
  12. CTF-Web-[极客大挑战 2019]Knife
  13. WBE15_HttpServletRequest
  14. 匿名发送邮件python_邮箱伪造之搭建匿名SMTP服务器
  15. 高并发之阿里云弹性伸缩的使用记录
  16. SpringDataJPA(二):SpringDataJPA的运行原理以及基本操作
  17. AR涂涂乐⭐六、 UGUI精灵格式、自动延迟截图、优化“4”、移出扫描框终止截图进程
  18. 精诚CRMPM系统应该要有哪些销售功能
  19. 【博客418】cpu平坦模型和分段模型
  20. Kubernetes 可扩展性简介

热门文章

  1. CF1286D-LCC【动态dp,数学期望】
  2. Loj#2880-「JOISC 2014 Day3」稻草人【CDQ分治,单调栈,二分】
  3. P3181-[HAOI2016]找相同字符【SAM】
  4. P2444-[POI2000]病毒【AC自动机】
  5. jzoj1610(初中)-导弹【最大匹配,最短路,二分答案】
  6. ssl1056-金明的预算方案【dp之有依赖的背包】
  7. 【Floyed】工厂的烦恼(ssl 1762)
  8. 4、oracle数据库的查询基础
  9. Spark入门(十七)之单表关联
  10. 汇编语言(二十五)之成绩分段统计