AES 256 Nodejs在C#.Net中进行加密和解密

如何解决AES 256 Nodejs在C#.Net中进行加密和解密

我尝试在C#中解密的数据是使用Nodejs中的AES-256算法加密的,代码如下。

const crypto = require('crypto');
const validator = require('validator');
const algorithm = 'aes256';
const inputEncoding = 'utf8';
const outputEncoding = 'hex';
const iv = crypto.randomBytes(16)

function encrypt(key,text) {
key = processKey(key);
let cipher = crypto.createCipheriv(algorithm,key,iv);
let ciphered = cipher.update(text,inputEncoding,outputEncoding);
ciphered += cipher.final(outputEncoding);
return ciphered;
}

现在,我获得了长度为32的加密数据(如“ 1234567304e07a5d2e93fbeefd0e417e”)和长度为32的密钥(如“ 123456673959499f9d37623168b2c977”)。

我正在尝试使用下面的c#代码对同一内容进行解密,并由于“要解密的数据长度无效”而收到错误消息。

public static string Decrypt(string combinedString,string keyString)
{
    string plainText;
    byte[] combinedData = StringToByteArray(combinedString);
    Aes aes = Aes.Create();
    aes.Key = Encoding.UTF8.GetBytes(keyString);
    byte[] iv = new byte[aes.BlockSize / 8];
    byte[] cipherText = new byte[combinedData.Length - iv.Length];
    Array.Copy(combinedData,iv,iv.Length);
    Array.Copy(combinedData,iv.Length,cipherText,cipherText.Length);
    aes.IV = iv;
    aes.Mode = CipherMode.CBC;
    ICryptoTransform decipher = aes.CreateDecryptor(aes.Key,aes.IV);

    using (MemoryStream ms = new MemoryStream(cipherText))
    {
        using (CryptoStream cs = new CryptoStream(ms,decipher,CryptoStreamMode.Read))
        {
            using (StreamReader sr = new StreamReader(cs))
            {
                plainText = sr.ReadToEnd();                 
            }
        }

        return plainText;
    }
}
public static byte[] StringToByteArray(string hex) {
return Enumerable.Range(0,hex.Length)
                 .Where(x => x % 2 == 0)
                 .Select(x => Convert.ToByte(hex.Substring(x,2),16))
                 .ToArray();
}

下面是Node.js中的解密代码,效果很好

const crypto = require('../functions/crypto');
const assert = require('assert');
const { v4: uuidv4 } = require('uuid');
describe('crypto module',function() {
it('should work',function(done) {
    const toHash = 'Octomate';
    const hashKey = uuidv4();

    const hash = crypto.encrypt(hashKey,toHash);
    const decrypted = crypto.decrypt(hashKey,hash);

    assert.strictEqual(toHash,decrypted);
    done();
});
});

解决方法

发布的NodeJS在CBC模式下使用AES-256执行加密。明文用UTF8编码,密文用十六进制编码。此外,生成随机IV并将其用于加密。由于方法processKey尚未发布,因此将不作进一步考虑,因此,以下NodeJS代码用于派生用于解密的C#代码:

const crypto = require('crypto');
const validator = require('validator');
const algorithm = 'aes256';
const inputEncoding = 'utf8';
const outputEncoding = 'hex';
const iv = crypto.randomBytes(16)

function encrypt(key,text) {
    //key = processKey(key);    // not posted
    let cipher = crypto.createCipheriv(algorithm,key,iv);
    let ciphered = cipher.update(text,inputEncoding,outputEncoding);
    ciphered += cipher.final(outputEncoding);
    return ciphered;
}

const key = '123456673959499f9d37623168b2c977';
const text = 'The quick brown fox jumps over the lazy dog'
const encrypted = encrypt(key,text);

console.log("IV (hex):         " + iv.toString('hex'));
console.log("Ciphertext (hex): " + encrypted);

使用发布的键123456673959499f9d37623168b2c977和纯文本The quick brown fox jumps over the lazy dog会产生以下输出:

IV (hex):         850bd88afd08c4ea14e75276277644f0
Ciphertext (hex): 5167ac87ebc79d5240255ff687c6bc8981c8791c353367a2e238a10e0983bf16e230ccf0511096f60c224b99927b3364

请注意,由于随机IV,每次加密都会生成不同的密文。

可以使用C#进行解密,如下所示:

string ciphertext = "5167ac87ebc79d5240255ff687c6bc8981c8791c353367a2e238a10e0983bf16e230ccf0511096f60c224b99927b3364";
string key = "123456673959499f9d37623168b2c977";
string iv = "850bd88afd08c4ea14e75276277644f0";
string decryptedText = Decrypt(ciphertext,iv);
Console.WriteLine("Decrypted text: " + decryptedText);

使用

public static string Decrypt(string ciphertextHex,string keyUtf8,string ivHex)
{
    byte[] ciphertext = StringToByteArray(ciphertextHex);
    byte[] iv = StringToByteArray(ivHex);

    string plaintext = "";
    using (Aes aes = Aes.Create())
    {
        aes.Key = Encoding.UTF8.GetBytes(keyUtf8);
        aes.IV = iv;
        aes.Mode = CipherMode.CBC;          // default
        aes.Padding = PaddingMode.PKCS7;    // default

        ICryptoTransform decipher = aes.CreateDecryptor(aes.Key,aes.IV);

        using (MemoryStream ms = new MemoryStream(ciphertext))
        {
            using (CryptoStream cs = new CryptoStream(ms,decipher,CryptoStreamMode.Read))
            {
                using (StreamReader sr = new StreamReader(cs,Encoding.UTF8)) // UTF8: default
                {
                    plaintext = sr.ReadToEnd();
                }
            }
        }
    }
    return plaintext;
}

// from https://stackoverflow.com/a/321404/9014097
public static byte[] StringToByteArray(string hex)
{
    return Enumerable.Range(0,hex.Length)
                     .Where(x => x % 2 == 0)
                     .Select(x => Convert.ToByte(hex.Substring(x,2),16))
                     .ToArray();
}

请注意以下几点:

  • 解密必须使用与加密相同的IV。由于IV的大小是已知的(与块大小相同),并且IV不是秘密的,因此通常将其放在字节级别的密文前面(未加密且没有分隔符),并且结果是Base64编码的。这被发送到接收器,Base64对其进行解码,然后分离接收到的数据。

    在发布的NodeJS代码中不会发生这种情况。然而,在您发布的C#代码 中,正是这种串联是预期的,因此将IV和密文分开。在我的评论中,我描述了NodeJS代码中用于连接IV和密文的更改,以便可以使用C#代码解密结果。

    由于NodeJS代码显然是主要代码,并且没有串联,因此在我的答案中 发布的C#代码也没有串联。但是,在这种情况下,必须通过IV。作为参数,否则,如上所述,就无法解密。

  • 不幸的是,发布的示例并不十分有用,因为您仅发布了密钥和密文(顺便说一下,因为它是十六进制编码的,所以只有16个字节长),但没有发布随机生成的IV。因此解密是不可能的。该示例也不能用于密文的比较,因为由于随机IV,每次都会生成不同的密文。

  • 由于NodeJS代码使用AES-256,因此密钥的大小必须为32个字节。因此,密钥可能是使用UTF8编码的。从这些值也可以进行十六进制编码,但这只会导致16字节的密钥。由于未发布方法processKey,因此不能排除对该密钥的进一步处理,因此在此不予考虑。

  • 不幸的是,发布的解密解密NodeJS代码也无济于事,因为未定义几种方法(例如crypto.encryptcrypto.decrypt),至少我看不到任何方法与发布的用于加密的NodeJS代码的有用关系。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-