c# - 如何创建 SHA-2 和 AES 加密字符串以在 .NET 的 HTTP 请求标头中使用?
问题描述
我正在尝试编写通过网络从外部 API 请求信息的客户端代码。
除了如何生成授权密钥的规定外,API 很简单(对我来说)。首先是一些上下文:开始需要 6 个字符串值:
- 令牌
- 密码
- 设备 ID
- 盐
- 组织 ID
- 给定密钥
现在是加密的东西。首先是 SHA2。
hashedString = SHA2(token + password + devId)
紧随其后的是 AES。
authKey = AES(salt + orgId + "=" + hashedString)
AES 参数指定如下:
- 模式 = 欧洲央行
- 填充 = PKCS5Padding
- 密钥 = givenKey
我的问题是我对密码学几乎一无所知。
下面是我试图完成上述操作的代码。
// Generate Authorisation key
byte[] fieldsBytes = Encoding.ASCII.GetBytes(token + password + devId);
byte[] keyBytes = Encoding.ASCII.GetBytes(secretKey);
SHA512 shaM = new SHA512Managed();
string hashedFields = Encoding.ASCII.GetString(shaM.ComputeHash(fieldsBytes));
byte[] encryptedBytes = EncryptStringToBytes_Aes(salt + orgId + "=" + hashedfields,
keyBytes, keyBytes);
string encryptedString = Encoding.ASCII.GetString(encryptedBytes);
private byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] encrypted;
// Create an Aes object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.Mode = CipherMode.ECB;
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor();
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
此代码从外部服务获得“401”。
我的第一个问题是似乎没有名为SHA2的 NET 方法。我能找到的最接近的是 SHA512,我不确定 SHA512 是否是 SHA2 的 .NET 实现。
其次,AES 的填充已被指定为 PKCS5Padding 但我能找到的最接近(命名方式)的是PKCS7,我不确定它与PKCS5有多么相似。
还有一个初始化向量 (IV)的问题,AES 参数没有指定,但我看到 C# AES 示例包括。在代码中,出于绝望,我已将其设置为与 Key 具有相同的值(我相信这是 API 所称的“秘密密钥”),但我尝试在不将 IV 设置为任何值的情况下发出请求,但仍然得到回一个401。
我可能还应该提到我正在使用ASCII编码来转换字节,因为我第一次尝试使用UTF8,但是当实际发出 HTTP 请求时,我收到一个异常,说头值(记住我们正在生成HTTP 请求标头中的授权密钥)只能以 ASCII 编码。
任何为我指明正确方向的帮助都将不胜感激,因为我对这些密码学的东西感到非常遗憾。
解决方案
别担心,加密货币会让人感觉非常复杂。我想你很接近。
SHA2是一系列哈希函数。在实践中,“SHA2”通常表示 SHA2-256 或偶尔表示 SHA2-512。我的猜测是您的外部 API 可能使用的是更常见的 SHA2-256。
crypto.stackexchange 上的这个答案解释说 PKCS#5 本质上是 PKCS#7 的一个子集。我敢打赌,您调用的 API 犯了与该答案中描述的相同的错误,并且应该真正调用它
PKCS7Padding
。你的代码很好!IV 与密钥(或只是 AES 的“密钥”)不同。对于每次加密运行,IV应该是随机的。您不应该从输入明文或输入密钥中派生它。幸运的是,
AesCryptoServiceProvider.GenerateIV()
会为您生成一个。不过,您可以将其添加到您的输出流中。用于
Encoding.ASCII.GetBytes()
获取明文和密钥字节对我来说很有意义。我不认为这会造成问题。
从这个对类似问题的出色答案中窃取(去给他们投票!),我会尝试这样的代码:
static byte[] AesEncrypt(byte[] data, byte[] key)
{
if (data == null || data.Length <= 0)
{
throw new ArgumentNullException($"{nameof(data)} cannot be empty");
}
if (key == null || key.Length != AesKeySize)
{
throw new ArgumentException($"{nameof(key)} must be length of {AesKeySize}");
}
using (var aes = new AesCryptoServiceProvider
{
Key = key,
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7
})
{
aes.GenerateIV();
var iv = aes.IV;
using (var encrypter = aes.CreateEncryptor(aes.Key, iv))
using (var cipherStream = new MemoryStream())
{
using (var tCryptoStream = new CryptoStream(cipherStream, encrypter, CryptoStreamMode.Write))
using (var tBinaryWriter = new BinaryWriter(tCryptoStream))
{
// prepend IV to data
cipherStream.Write(iv);
tBinaryWriter.Write(data);
tCryptoStream.FlushFinalBlock();
}
var cipherBytes = cipherStream.ToArray();
return cipherBytes;
}
}
}
除非这个 API 发生了其他奇怪的事情,否则我猜可能是上面的 #3 导致您的请求失败。
推荐阅读
- c - 使用 make 命令构建项目时出错,使用未声明的标识符“__compar_fn_t”
- numpy - 如何让 scipy.stats.truncnorm.rvs 使用 numpy.random.default_rng()?
- html - 复制电子邮件签名的正确方法是什么以及为什么电子邮件签名与从电子邮件客户端发送的签名不同
- android - 替换 Flutter 库中的 gradle 依赖项
- python - Python re 中注释的正则表达式
- javascript - 在 Node 和 React 中获取请求以检查登录信息
- python - 确定图被完全访问多长时间
- qt - Cmake AUTOMOC_SOURCE_GROUP 属性在 Visual Studio 中无效
- javascript - discord.js 机器人不响应命令
- vue.js - 保留导航抽屉上的标题和图标