ChaCha20-Poly1305 介绍

Java 11新增加了加密算法ChaCha20-Poly1305。

ChaCha20-Poly1305相关的名词需要解释一下:

ChaCha20是一种流式对称加密算法。

Poly1305是一种带密码的消息摘要算法。

ChaCha20-Poly1305是一种流式对称加密算法。

说明:我并没有找到Java 11中的Poly1305算法API,于是按照RFC7539实现了一下,见下文代码,为了便于对照原文,有的private函数命名采用下划线分割小写字母方式,不太符合Java规范。

ChaCha20 和 ChaCha20-Poly1305 的区别

这两种算法原理上是一致的。区别如下:

ChaCha20 是流式加密,密文长度和原文长度是相同的。

ChaCha20-Poly1305 在 ChaCha20 的基础上增加了Poly1305 算法运算结果。

ChaCha20 有四个输入:

明文 Plaintext

秘钥 Key

秘钥 Nonce

轮 Initial Counter,整数

ChaCha20-Poly1305 有三个输入,不需要“轮”,其他输入和ChaCha20 一样。

测试用例

Key = 00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f.

Nonce = (00:00:00:00:00:00:00:4a:00:00:00:00).

Initial Counter = 1.

Plaintext

000 4c 61 64 69 65 73 20 61 6e 64 20 47 65 6e 74 6c Ladies and Gentl

016 65 6d 65 6e 20 6f 66 20 74 68 65 20 63 6c 61 73 emen of the clas

032 73 20 6f 66 20 27 39 39 3a 20 49 66 20 49 20 63 s of '99: If I c

048 6f 75 6c 64 20 6f 66 66 65 72 20 79 6f 75 20 6f ould offer you o

064 6e 6c 79 20 6f 6e 65 20 74 69 70 20 66 6f 72 20 nly one tip for

080 74 68 65 20 66 75 74 75 72 65 2c 20 73 75 6e 73 the future, suns

096 63 72 65 65 6e 20 77 6f 75 6c 64 20 62 65 20 69 creen would be i

112 74 2e t.

ChaCha20 加密结果:

000 6e 2e 35 9a 25 68 f9 80 41 ba 07 28 dd 0d 69 81

016 e9 7e 7a ec 1d 43 60 c2 0a 27 af cc fd 9f ae 0b

032 f9 1b 65 c5 52 47 33 ab 8f 59 3d ab cd 62 b3 57

048 16 39 d6 24 e6 51 52 ab 8f 53 0c 35 9f 08 61 d8

064 07 ca 0d bf 50 0d 6a 61 56 a3 8e 08 8a 22 b6 5e

080 52 bc 51 4d 16 cc f8 06 81 8c e9 1a b7 79 37 36

096 5a f9 0b bf 74 a3 5b e6 b4 0b 8e ed f2 78 5e 42

112 87 4d

ChaCha20-Poly1305 加密结果:

000 6e 2e 35 9a 25 68 f9 80 41 ba 07 28 dd 0d 69 81

016 e9 7e 7a ec 1d 43 60 c2 0a 27 af cc fd 9f ae 0b

032 f9 1b 65 c5 52 47 33 ab 8f 59 3d ab cd 62 b3 57

048 16 39 d6 24 e6 51 52 ab 8f 53 0c 35 9f 08 61 d8

064 07 ca 0d bf 50 0d 6a 61 56 a3 8e 08 8a 22 b6 5e

080 52 bc 51 4d 16 cc f8 06 81 8c e9 1a b7 79 37 36

096 5a f9 0b bf 74 a3 5b e6 b4 0b 8e ed f2 78 5e 42

112 87 4d 81 db 63 fc b1 89 a0 31 21 ae 0a c7 2a 3f

128 1f 36

我们可以看到两者加密的结果是一致的,除了ChaCha20-Poly1305 加密后面多16个字节内容。

ChaCha20 加密主要代码:

byte[] chacha20(byte[] message, byte[] key, byte[] nonce, int counter) {

Key theKey = new SecretKeySpec(key, "ChaCha20");

ChaCha20ParameterSpec spec = new ChaCha20ParameterSpec(nonce, counter);

Cipher cipher = Cipher.getInstance("ChaCha20");

cipher.init(Cipher.ENCRYPT_MODE, theKey, spec);

return cipher.doFinal(message);

}

ChaCha20-Poly1305 加密主要代码:

byte[] chacha20Ploy1305(byte[] message, byte[] key, byte[] nonce) {

Key theKey = new SecretKeySpec(key, "ChaCha20-Poly1305");

AlgorithmParameterSpec spec = new IvParameterSpec(nonce);

Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305");

cipher.init(Cipher.ENCRYPT_MODE, theKey, spec);

return cipher.doFinal(message);

}

全部代码

import org.junit.Assert;

import org.junit.Test;

import javax.crypto.Cipher;

import javax.crypto.spec.ChaCha20ParameterSpec;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import java.math.BigInteger;

import java.security.Key;

import java.security.spec.AlgorithmParameterSpec;

public class ChaCha20Poly1305Test {

byte[] nonce = hex2bytes("00 00 00 00 00 00 00 4a 00 00 00 00");

byte[] key = hex2bytes("00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" +

"10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f");

byte[] message = hex2bytes("4c 61 64 69 65 73 20 61 6e 64 20 47 65 6e 74 6c" +

"65 6d 65 6e 20 6f 66 20 74 68 65 20 63 6c 61 73" +

"73 20 6f 66 20 27 39 39 3a 20 49 66 20 49 20 63" +

"6f 75 6c 64 20 6f 66 66 65 72 20 79 6f 75 20 6f" +

"6e 6c 79 20 6f 6e 65 20 74 69 70 20 66 6f 72 20" +

"74 68 65 20 66 75 74 75 72 65 2c 20 73 75 6e 73" +

"63 72 65 65 6e 20 77 6f 75 6c 64 20 62 65 20 69" +

"74 2e");

@Test

public void testChaCha20Poly1305() {

byte[] encoded = chacha20Ploy1305Encrypt(message, key, nonce);

byte[] expected = hex2bytes("6e 2e 35 9a 25 68 f9 80 41 ba 07 28 dd 0d 69 81" +

"e9 7e 7a ec 1d 43 60 c2 0a 27 af cc fd 9f ae 0b" +

"f9 1b 65 c5 52 47 33 ab 8f 59 3d ab cd 62 b3 57" +

"16 39 d6 24 e6 51 52 ab 8f 53 0c 35 9f 08 61 d8" +

"07 ca 0d bf 50 0d 6a 61 56 a3 8e 08 8a 22 b6 5e" +

"52 bc 51 4d 16 cc f8 06 81 8c e9 1a b7 79 37 36" +

"5a f9 0b bf 74 a3 5b e6 b4 0b 8e ed f2 78 5e 42" +

"87 4d 81 db 63 fc b1 89 a0 31 21 ae 0a c7 2a 3f" +

"1f 36");

Assert.assertArrayEquals(expected, encoded);

byte[] origin = chacha20Ploy1305Decrypt(encoded, key, nonce);

Assert.assertArrayEquals(origin, message);

}

@Test

public void testChaCha20() {

int counter = 1;

byte[] encoded = chacha20Encrypt(message, key, nonce, counter);

byte[] expected = hex2bytes("6e 2e 35 9a 25 68 f9 80 41 ba 07 28 dd 0d 69 81" +

"e9 7e 7a ec 1d 43 60 c2 0a 27 af cc fd 9f ae 0b" +

"f9 1b 65 c5 52 47 33 ab 8f 59 3d ab cd 62 b3 57" +

"16 39 d6 24 e6 51 52 ab 8f 53 0c 35 9f 08 61 d8" +

"07 ca 0d bf 50 0d 6a 61 56 a3 8e 08 8a 22 b6 5e" +

"52 bc 51 4d 16 cc f8 06 81 8c e9 1a b7 79 37 36" +

"5a f9 0b bf 74 a3 5b e6 b4 0b 8e ed f2 78 5e 42" +

"87 4d");

Assert.assertArrayEquals(expected, encoded);

byte[] origin = chacha20Decrypt(encoded, key, nonce, counter);

Assert.assertArrayEquals(origin, message);

}

@Test

public void testPoly1305() {

Poly1305 poly1305 = new Poly1305();

message = hex2bytes("43 72 79 70 74 6f 67 72 61 70 68 69 63 20 46 6f" +

"72 75 6d 20 52 65 73 65 61 72 63 68 20 47 72 6f" +

"75 70");

key = hex2bytes("85 d6 be 78 57 55 6d 33 7f 44 52 fe 42 d5 06 a8" +

"01 03 80 8a fb 0d b2 fd 4a bf f6 af 41 49 f5 1b");

byte[] expected = hex2bytes("a8 06 1d c1 30 51 36 c6 c2 2b 8b af 0c 01 27 a9");

byte[] hashValue = poly1305.ploy1305(message, key);

Assert.assertArrayEquals(expected, hashValue);

}

public byte[] hex2bytes(String hex) {

hex = hex.replaceAll("[: ]", "");

byte[] result = new byte[hex.length() / 2];

for (int i = 0; i < result.length; i++) {

String hexByte = hex.substring(i * 2, i * 2 + 2);

result[i] = (byte) Integer.parseInt(hexByte, 16);

}

return result;

}

public byte[] chacha20Encrypt(byte[] message, byte[] key, byte[] nonce, int counter) {

return chacha20(message, key, nonce, counter, Cipher.ENCRYPT_MODE);

}

public byte[] chacha20Decrypt(byte[] message, byte[] key, byte[] nonce, int counter) {

return chacha20(message, key, nonce, counter, Cipher.DECRYPT_MODE);

}

public byte[] chacha20Ploy1305Encrypt(byte[] message, byte[] key, byte[] nonce) {

return chacha20Ploy1305(message, key, nonce, Cipher.ENCRYPT_MODE);

}

public byte[] chacha20Ploy1305Decrypt(byte[] message, byte[] key, byte[] nonce) {

return chacha20Ploy1305(message, key, nonce, Cipher.DECRYPT_MODE);

}

private byte[] chacha20(byte[] message, byte[] key, byte[] nonce, int counter, int mode) {

// nonce 长度必须为 12字节

if (nonce == null || nonce.length != 12) {

throw new IllegalArgumentException("nonce must be 12 bytes in length");

}

// 密钥的长度必须为256位,即32字节

if (key == null || key.length != 32) {

throw new IllegalArgumentException("key length must be 256 bits");

}

Key theKey = new SecretKeySpec(key, "ChaCha20");

ChaCha20ParameterSpec spec = new ChaCha20ParameterSpec(nonce, counter);

try {

Cipher cipher = Cipher.getInstance("ChaCha20");

cipher.init(mode, theKey, spec);

return cipher.doFinal(message);

} catch (Exception e) {

throw new RuntimeException(e);

}

}

private byte[] chacha20Ploy1305(byte[] message, byte[] key, byte[] nonce, int mode) {

// nonce 长度必须为 12字节

if (nonce == null || nonce.length != 12) {

throw new IllegalArgumentException("nonce must be 12 bytes in length");

}

// 密钥的长度必须为256位,即32字节

if (key == null || key.length != 32) {

throw new IllegalArgumentException("key length must be 256 bits");

}

Key theKey = new SecretKeySpec(key, "ChaCha20-Poly1305");

AlgorithmParameterSpec spec = new IvParameterSpec(nonce);

try {

Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305");

cipher.init(mode, theKey, spec);

return cipher.doFinal(message);

} catch (Exception e) {

throw new RuntimeException(e);

}

}

}

class Poly1305 {

public byte[] ploy1305(byte[] msg, byte[] key) {

BigInteger r = le_bytes_to_num(key, 0, 16);

r = clamp(r);

BigInteger s = le_num(key, 16, 16);

BigInteger a = BigInteger.ZERO;

BigInteger p = BigInteger.ONE.shiftLeft(130).add(BigInteger.valueOf(-5));

for (int i = 1; i <= ceilMod(msg.length, 16); i++) {

int len = 16;

if (i == ceilMod(msg.length, 16) && (msg.length % 16 != 0)) {

len = msg.length % 16;

}

BigInteger n = le_bytes_to_num_pad(msg, (i - 1) * 16, len);

a = a.add(n);

a = r.multiply(a).mod(p);

}

a = a.add(s);

return num_to_16_le_bytes(a);

}

public long ceilMod(long value, long mod) {

long result = value % mod;

if (result == 0) {

return value / mod;

} else {

return value / mod + 1;

}

}

public byte[] hex2bytes(String s) {

s = s.replaceAll("[: ]", "");

byte[] result = new byte[s.length() / 2];

for (int i = 0; i < result.length; i++) {

String hex = s.substring(i * 2, i * 2 + 2);

result[i] = (byte) Integer.parseInt(hex, 16);

}

return result;

}

public long toUnsigned(byte b) {

return b >= 0 ? b : (b + Byte.MAX_VALUE * 2L + 2);

}

private byte[] num_to_16_le_bytes(BigInteger v) {

byte[] value = v.toByteArray();

byte[] result = new byte[16];

for (int i = 0; i < 16; i++) {

result[i] = value[value.length - 1 - i];

}

return result;

}

private BigInteger le_bytes_to_num(byte[] b, int off, int len) {

StringBuilder sb = new StringBuilder();

for (int i = off + len - 1; i >= off; i--) {

sb.append(String.format("%02x", toUnsigned(b[i])));

}

return new BigInteger(sb.toString(), 16);

}

private BigInteger le_bytes_to_num_pad(byte[] b, int off, int len) {

StringBuilder sb = new StringBuilder();

sb.append("01");

for (int i = off + len - 1; i >= off; i--) {

sb.append(String.format("%02x", toUnsigned(b[i])));

}

return new BigInteger(sb.toString(), 16);

}

private BigInteger le_num(byte[] b, int off, int len) {

byte[] bs = new byte[len];

for (int i = 0; i < len; i++) {

bs[i] = b[len - 1 - i + off];

}

return new BigInteger(bs, 0, len);

}

private BigInteger clamp(BigInteger r) {

BigInteger magicNumber = new BigInteger("0ffffffc0ffffffc0ffffffc0fffffff", 16);

return r.and(magicNumber);

}

}

相关文章

chacha20加密c语言算法,Java 11的新加密算法ChaCha20-Poly1305相关推荐

  1. 阿诺德图像加密c语言,基于Arnold变换的数字图像加密算法

    目前常用的图像置乱方法有Arnold变换.幻方变换.Tangram算法.Conway游戏.Gray码变换等.Arnold变换算法简单且具有周期性,所以在图像信息隐藏方面得到了很好的应用.下面我就给大家 ...

  2. Java 11:新的HTTP客户端API

    在Java 11中,已将最初在Java 9中引入的孵化HTTP客户端API进行了标准化. 它使连接URL,管理请求参数,cookie和会话更加容易,甚至支持异步请求和websocket. 回顾一下,这 ...

  3. java 异或加密 c语言解密,java对文件简单的加密解密(异或运算)

    package xxx; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; i ...

  4. 阿诺德图像加密c语言,基于Arnold置乱的数字图像加密算法(二)

    前文我们介绍了基于Arnold置乱的数字图像加密算法的两种图像置乱变换,今天我们介绍的是另外三种图像置乱变换:基于骑士巡游的图像置乱变换.基于Arnold变换的数字图像置乱和基于仿射变换的置乱变换. ...

  5. Java 11 – ChaCha20-Poly1305加密示例

    本文向您展示如何使用RFC 7539中定义的ChaCha20-Poly1305算法对消息进行加密和解密. PS ChaCha20-Poly1305加密算法可从Java 11获得. 1.常见问题 一些常 ...

  6. Java 11 – ChaCha20加密示例

    在本文中,我们将向您展示如何使用RFC 7539中定义的ChaCha20流密码对消息进行加密和解密. PS ChaCha20流密码可从Java 11获得,请参阅JEP 329 . 注意 您可能对此Ch ...

  7. IntelliJ IDEA 使用 Java 11新特性以及Java 8 以来的Java 11新特性介绍

    文章目录 Java 11 安装 IDEA 设置 特性1:lambda表达式中允许使用var 特性2: String新增REPEAT 方法,方便拷贝字符串 特性3: 文件读写更方便:readString ...

  8. 一文读懂Java 11的ZGC为何如此高效

    导读:GC是大部分现代语言内置的特性,Java 11 新加入的ZGC号称可以达到10ms 以下的 GC 停顿,本文作者对这一新功能进行了深入解析.同时还对还对这一新功能带来的其他可能性做了展望.ZGC ...

  9. Java 11将于本月25日发布,新特性一览

    作者:漫画编程 来源:漫画编程 2017年8月,JCP执行委员会提出将Java的发布频率改为每六个月一次.该决定将在Java 9正式发布之后开始实行. 2018年3月,Java 10如期而至.目前已经 ...

最新文章

  1. 面试官问:服务的心跳机制与断线重连,Netty底层是怎么实现的?懵了
  2. mac邮件过滤器SpamSieve,支持任意类型的任意数量的电子邮件帐户
  3. 兼容多种屏幕分辨率的通栏大图实现方法
  4. python第七关再来一盘_7、 Python系列,七,的,集合
  5. Spark SQL 1.x之SQL Context使用
  6. java利用正则截取字符串中的数字
  7. firefox 开发sdk
  8. 【定时任务】Quartz用法详解
  9. 速成pytorch学习——6天Dataset和DataLoader
  10. npm login 登录失败,报E500 Internal Server Error - PUT https://registry.npm.taobao.org/-/user/org.couchdb
  11. go语言学习之切片、字典、defer语句
  12. node koa2 玩起来都是中间件啊
  13. linux内核多个补丁,一个令人惊叹的Linux内核补丁
  14. 新手python爬虫代码-Python爬虫实战之取电影天堂,,新手练手项目
  15. Python游戏嗷大喵快跑设计
  16. oracle 人民币符号,人民币的符号的正确表示法?一杠?两杠?
  17. 外包or外派岗,可以去?
  18. 谷歌账户在别的网上登过_如何在Google帐户之间转移联系人
  19. Worthington 脱氧核糖核酸酶说明书
  20. 百度网盘满速下载文件

热门文章

  1. JAVA CDI 学习(1) - @Inject基本用法
  2. 【机试题(实现语言:python3)】学英语-递归或字符串
  3. 微软提前发新版音乐播放器 阻击苹果新iPod
  4. springboot一键启动
  5. 动物细胞无血清培养基的发展和应用
  6. 图像处理神经网络是什么,图像处理神经网络模型
  7. 计算机二级(c语言)重难点归纳--公共基础部分--计算机系统
  8. python练习实例一 互不相同且不重复的数字组合
  9. python有四个数字_Python生成0-9任意4位数字组合的方法
  10. 语言模型训练工具SRILM