C# 中的 AEAD_AES_256_GCM
- 注意:AEAD_AES_256_GCM Key的长度必须是32位,nonce的长度必须是12位,附加数据有可能为空值。AEAD_AES_128_GCM Key的长度必须是16位,nonce的长度必须是12位,附加数据有可能为空值。
使用中AEAD_AES_256_GCM还是AEAD_AES_128_GCM加密,是根据key的长度来决定的。
size = key.Length * 8
256 = 32 * 8, AEAD_AES_256_GCM的key长度必须是 32 位。
128 = 16 * 8, AEAD_AES_128_GCM的key长度必须是 16 位。
英文好的可以看这个文档rfc5116
使用官方AesGcm类
自aspnetcore3.0之后,System.Security.Cryptography支持 AES_GCM,不支持.net framework。在加密时,请使用AesGcmEncryptToBase64_WithTag方法,这个方法的结果包含了tag (authentication tag)。加密结果最后面的16位字符就是tag,但是官方的加密方法没有帮我们拼接上。
/// <summary>
/// 使用 AesGcm 解密
/// </summary>
/// <param name="key">key32位字符</param>
/// <param name="nonce">随机串12位</param>
/// <param name="encryptedData">密文(Base64字符)</param>
/// <param name="associatedData">(可能null)</param>
/// <returns></returns>
static string AesGcmDecryptFromBase64(string key, string nonce, string encryptedData, string associatedData)
{
var keyBytes = Encoding.UTF8.GetBytes(key);
var nonceBytes = Encoding.UTF8.GetBytes(nonce);
var associatedBytes = associatedData == null ? null : Encoding.UTF8.GetBytes(associatedData); var encryptedBytes = Convert.FromBase64String(encryptedData);
//tag size is 16
var cipherBytes = encryptedBytes[..^16];
var tag = encryptedBytes[^16..];
var decryptedData = new byte[cipherBytes.Length];
using var cipher = new AesGcm(keyBytes);
cipher.Decrypt(nonceBytes, cipherBytes, tag, decryptedData, associatedBytes);
return Encoding.UTF8.GetString(decryptedData);
} /// <summary>
/// 使用 AesGcm AEAD_AES_256_GCM 加密,不要在正式环境中使用这个方法。因为在解密时不知道tag,除非额外返回tag。
/// </summary>
/// <param name="key">key32位字符</param>
/// <param name="nonce">随机串12位</param>
/// <param name="plainData">明文</param>
/// <param name="associatedData">附加数据(可能null)</param>
/// <returns>只返回加密数据不包含authentication tag</returns>
static string AesGcmEncryptToBase64(string key, string nonce, string plainData, string associatedData)
{
var keyBytes = Encoding.UTF8.GetBytes(key);
var nonceBytes = Encoding.UTF8.GetBytes(nonce);
var associatedBytes = associatedData == null ? null : Encoding.UTF8.GetBytes(associatedData); var plainBytes = Encoding.UTF8.GetBytes(plainData);
var cipherBytes = new byte[plainBytes.Length];
using var cipher = new AesGcm(keyBytes);
//tag size must be is 16
var tag = new byte[16];
cipher.Encrypt(nonceBytes, plainBytes, cipherBytes, tag, associatedBytes); return Convert.ToBase64String(cipherBytes);
} /// <summary>
/// 使用 AesGcm进行AEAD_AES_256_GCM加密
/// </summary>
/// <param name="key">key32位字符</param>
/// <param name="nonce">随机串12位</param>
/// <param name="plainData">明文</param>
/// <param name="associatedData">附加数据(可能null)</param>
/// <returns>base64(加密后数据 + authentication tag)</returns>
static string AesGcmEncryptToBase64_WithTag(string key, string nonce, string plainData, string associatedData)
{
var keyBytes = Encoding.UTF8.GetBytes(key);
var nonceBytes = Encoding.UTF8.GetBytes(nonce);
var associatedBytes = associatedData == null ? null : Encoding.UTF8.GetBytes(associatedData); var plainBytes = Encoding.UTF8.GetBytes(plainData);
var cipherBytes = new byte[plainBytes.Length];
//tag size is 16
var tag = new byte[16];
using var cipher = new AesGcm(keyBytes);
cipher.Encrypt(nonceBytes, plainBytes, cipherBytes, tag, associatedBytes); var cipherWithTag = new byte[cipherBytes.Length + tag.Length];
Buffer.BlockCopy(cipherBytes, 0, cipherWithTag, 0, cipherBytes.Length);
Buffer.BlockCopy(tag, 0, cipherWithTag, cipherBytes.Length, tag.Length); return Convert.ToBase64String(cipherWithTag);
}
测试代码
var text = "{'A':123, count:'10', isOk:false, body:{'Text':'select * from table_A where name=@_p1', result:[{'id':1, 'age':23}]}}";
//KEY 必须是两个32位
var key = "1234567890_1234567890_1234567890";
var nonce = "77d0a5ff3937";//Guid.NewGuid().ToString("N").Substring(0, 12);
var associated = "6df132d42d0b4581"; //Guid.NewGuid().ToString("N").Substring(0, 16);
var pythonResult = "PrTO/594j0CYMi2CQF9IFIp7UNkiTtIiIUbmR+jv1c1iO8Ng/HDFHDjL2t0DYo7xo5Vr0O0fUg9hD3bfCoomP+taVaPrW2kJbPTiFXkohXk3T80lQIdWP5lrl21vJvZO3MbmvshyjU+Oxk7pSnjiE5mw/sPXBs4jzS5wtvLUgHvWGaNxzw==";
Console.WriteLine();
var cipherText = AesGcmEncryptToBase64(key, nonce, text, nonce);
Console.WriteLine($"原始密文Base64 :\t{cipherText}");
//Console.WriteLine($"密文tag Base64:\t\t{AesGcmEncryptToBase64(keyBytes, nonceBytes, text, associatedBytes)}");
Console.WriteLine($"Python GCM密文 :\t{pythonResult}");
var cryptText1 = AesGcmEncryptByBouncyCastle(key, nonce, text, associated);
Console.WriteLine($"BouncyCastle密文: \t{cryptText1} ");
var cryptText2 = AesGcmEncryptToBase64_WithTag(key, nonce, text, associated);
Console.WriteLine($"密文+Tag Base64 : \t{cryptText2} ");
Console.WriteLine();
Console.WriteLine();
var t30 = AesGcmDecryptByBouncyCastle(key, nonce, pythonResult, associated);
Console.WriteLine($"BouncyCastle 解密 Python :{t30} \tisOk:{text == t30}");
var t40 = AesGcmDecryptFromBase64(key, nonce, pythonResult, associated);
Console.WriteLine($"AesGcm 解密 Python :{t40} \tisOk:{text == t40}");
Console.WriteLine();
Console.WriteLine();
var t31 = AesGcmDecryptByBouncyCastle(key, nonce, cryptText1, associated);
Console.WriteLine($"BouncyCastle 解密 BouncyCastle:{t31} \tisOk:{text == t31}");
var t41 = AesGcmDecryptFromBase64(key, nonce, cryptText1, associated);
Console.WriteLine($"AesGcm 解密 BouncyCastle:{t41} \tisOk:{text == t41}");
Console.WriteLine();
Console.WriteLine();
var t32 = AesGcmDecryptByBouncyCastle(key, nonce, cryptText2, associated);
Console.WriteLine($"BouncyCastle 解密 密文+Tag :{t32} \tisOk:{text == t32}");
var t42 = AesGcmDecryptFromBase64(key, nonce, cryptText2, associated);
Console.WriteLine($"AesGcm 解密 密文+Tag :{t42} \tisOk:{text == t42}");
转载来源:https://www.cnblogs.com/jzblive/p/14386757.html
C# 中的 AEAD_AES_256_GCM的更多相关文章
- Python开源框架
info:更多Django信息url:https://www.oschina.net/p/djangodetail: Django 是 Python 编程语言驱动的一个开源模型-视图-控制器(MVC) ...
- 项目中使用libsodium扩展
前段时间研究了微信小微商户,地址:https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=19_11 其接口操作中需要下载证书针对返回的密 ...
- Java中的微信支付(2):API V3 微信平台证书的获取与刷新
1. 前言 在Java中的微信支付(1):API V3版本签名详解一文中胖哥讲解了微信支付V3版本API的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API证书对参数进行加签,微信 ...
- mapreduce中一个map多个输入路径
package duogemap; import java.io.IOException; import java.util.ArrayList; import java.util.List; imp ...
- Hadoop 中利用 mapreduce 读写 mysql 数据
Hadoop 中利用 mapreduce 读写 mysql 数据 有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...
- Python中的多进程与多线程(一)
一.背景 最近在Azkaban的测试工作中,需要在测试环境下模拟线上的调度场景进行稳定性测试.故而重操python旧业,通过python编写脚本来构造类似线上的调度场景.在脚本编写过程中,碰到这样一个 ...
- .NET Core中的认证管理解析
.NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...
- Angular杂谈系列1-如何在Angular2中使用jQuery及其插件
jQuery,让我们对dom的操作更加便捷.由于其易用性和可扩展性,jQuer也迅速风靡全球,各种插件也是目不暇接. 我相信很多人并不能直接远离jQuery去做前端,因为它太好用了,我们以前做的东西大 ...
- 关于CryptoJS中md5加密以及aes加密的随笔
最近项目中用到了各种加密,其中就包括从没有接触过得aes加密,因此从网上各种查,官方的一种说法: 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学 ...
- In-Memory:在内存中创建临时表和表变量
在Disk-Base数据库中,由于临时表和表变量的数据存储在tempdb中,如果系统频繁地创建和更新临时表和表变量,大量的IO操作集中在tempdb中,tempdb很可能成为系统性能的瓶颈.在SQL ...
随机推荐
- PHP中的__autoload()和spl_autoload_register()
php的__autoload函数是一个魔术函数,在这个函数出现之前,如果一个php文件里引用了100个对象,那么这个文件就需要使用include或require引进100个类文件,这将导致该php文件 ...
- windows安装PHP的redis
一定要先看vc版本和位 配置php的redis扩展 以php7.3 nts版为例,不同的php版本对应不通的redis扩展:下载扩展文件:https://windows.php.net/downloa ...
- [oeasy]python0033_回车_carriage_return_figlet_字体变大
回到开头 回忆上次内容 进程前后台切换 ctrl + z 把当前进程切换到后台并暂停 jobs 查看所有作业 用 fg 可以把后台进程再切回前台 fg %1 可以把指定的任务切回前台 用 bg 可 ...
- Visual Studio 必备插件集合:AI 助力开发
一.前言 2024年AI浪潮席卷全球,编程界迎来全新的挑战与机遇.智能编程.自动化测试.代码审查,这一切都得益于AI技术的迅猛发展,它正在重塑开发者的日常,让编写代码变得更加高效.智能. 精选出最受 ...
- 顺序表_C
// Code file created by C Code Develop #include "ccd.h" #include "stdio.h" #incl ...
- 图解翻转单向链表,超详细(python语言实现)
节点类: 1 class ListNode(object): 2 def __init__(self, x): 3 self.val = x 4 slef.next = None 反转单向链表的函数如 ...
- 提高 C# 的生产力:C# 13 更新完全指南
前言 预计在 2024 年 11 月,C# 13 将与 .NET 9 一起正式发布.今年的 C# 更新主要集中在 ref struct 上进行了许多改进,并添加了许多有助于进一步提高生产力的便利功能. ...
- PHP转Go系列 | Carbon 时间处理工具的使用姿势
大家好,我是码农先森. 在日常的开发过程中经常会遇到对时间的处理,比如将时间戳进行格式化.获取昨天或上周或上个月的时间.基于当前时间进行加减等场景的使用.在 PHP 语言中有一个针对时间处理的原生函数 ...
- 【Spring Data JPA】02 快速上手
完成一个CRUD - 创建工程导入依赖坐标 - 配置Spring的配置文件 - 配置ORM的实体类,绑定映射关系 - 编写一个符合SpringDataJpa的dao接口 Maven依赖坐标 <p ...
- 【Git】04 文件删除
版本分支的概念提示: 工作区就是我们的Git本地仓库,也就是一个很普通的目录 . 通过ADD指令添加文件到暂存区中, 在通过COMMIT指令提交到版本分支, 所谓的版本分支,就是就是这个蓝色的Mast ...