You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将ASP.NET中基于SHA1的加解密逻辑迁移至Node.js

Node.js Implementation for Matching C# SHA1-Based Encryption/Decryption

Hey there! I see you're looking to port your C# SHA1-based encryption logic to Node.js for your new Angular + Node project—let's break this down step by step to ensure it matches exactly with your existing ASP.NET code.

First, let's recap the key details from your C# code that we need to replicate:

  • Uses PBKDF1 (via PasswordDeriveBytes with SHA1) to generate the encryption key
  • AES-256-CBC encryption (since RijndaelManaged with 256-bit key defaults to AES)
  • Specific encodings: ASCII for IV/salt, UTF8 for plaintext, Base64 for ciphertext
  • Fixed iteration count and key size

Node.js has a built-in crypto module that we can use, but we'll need to manually implement PBKDF1 since it's not natively supported (Node.js defaults to PBKDF2). Here's the complete implementation:

Step 1: Define Constants (Match C# Static Variables)

const crypto = require('crypto');

// Exact matches to your C# static variables
const passPhrase = "Paaaa5p***";
const saltValue = "s@1t***lue";
const hashAlgorithm = "sha1";
const passwordIterations = 2;
const initVector = "@1B2c3D4e5F6****";
const keySize = 256; // Key size in bits

Step 2: Replicate C#'s PasswordDeriveBytes Logic

C#'s PasswordDeriveBytes uses PBKDF1, which repeats hashing the passphrase + salt for the specified iterations. If the required key length exceeds SHA1's 20-byte output, it recursively generates additional bytes. Here's how to mimic that:

// Mimics C#'s PasswordDeriveBytes (PBKDF1 with SHA1)
function passwordDeriveBytes(passphrase, salt, iterations, keyLength) {
    let derivedKey = Buffer.from(passphrase, 'utf8');
    
    // Iterate the hash process as specified
    for (let i = 0; i < iterations; i++) {
        const hash = crypto.createHash(hashAlgorithm);
        hash.update(Buffer.concat([derivedKey, salt]));
        derivedKey = hash.digest();
    }
    
    // Generate extra bytes if needed (when keyLength > SHA1's 20 bytes)
    if (derivedKey.length < keyLength) {
        const extraBytes = passwordDeriveBytes(passphrase, derivedKey, 1, keyLength - derivedKey.length);
        derivedKey = Buffer.concat([derivedKey, extraBytes]);
    }
    
    return derivedKey.slice(0, keyLength);
}

Step 3: Encryption Function (Matches EncryptText)

This function mirrors your C# encryption logic, using the same encoding and AES parameters:

function encryptText(text) {
    // Convert IV and salt to ASCII bytes (matches C#'s Encoding.ASCII.GetBytes)
    const initVectorBytes = Buffer.from(initVector, 'ascii');
    const saltValueBytes = Buffer.from(saltValue, 'ascii');
    // Convert plaintext to UTF8 bytes (matches C#'s Encoding.UTF8.GetBytes)
    const plainTextBytes = Buffer.from(text, 'utf8');
    
    // Generate the 256-bit key (32 bytes = 256/8)
    const keyBytes = passwordDeriveBytes(passPhrase, saltValueBytes, passwordIterations, keySize / 8);
    
    // Create AES-CBC cipher (C#'s RijndaelManaged defaults to AES-CBC with PKCS7 padding)
    const cipher = crypto.createCipheriv('aes-256-cbc', keyBytes, initVectorBytes);
    
    // Encrypt and combine results
    let cipherText = cipher.update(plainTextBytes);
    cipherText = Buffer.concat([cipherText, cipher.final()]);
    
    // Convert to Base64 string (matches C#'s Convert.ToBase64String)
    return cipherText.toString('base64');
}

Step 4: Decryption Function (Matches DecryptText)

This reverses the encryption process exactly like your C# code:

function decryptText(encryptText) {
    // Convert IV and salt to ASCII bytes
    const initVectorBytes = Buffer.from(initVector, 'ascii');
    const saltValueBytes = Buffer.from(saltValue, 'ascii');
    // Convert Base64 ciphertext to byte array (matches C#'s Convert.FromBase64String)
    const cipherTextBytes = Buffer.from(encryptText, 'base64');
    
    // Generate the same 256-bit key
    const keyBytes = passwordDeriveBytes(passPhrase, saltValueBytes, passwordIterations, keySize / 8);
    
    // Create AES-CBC decipher
    const decipher = crypto.createDecipheriv('aes-256-cbc', keyBytes, initVectorBytes);
    
    // Decrypt and combine results
    let plainText = decipher.update(cipherTextBytes);
    plainText = Buffer.concat([plainText, decipher.final()]);
    
    // Convert UTF8 bytes back to string (matches C#'s Encoding.UTF8.GetString)
    return plainText.toString('utf8');
}

Step 5: Test the Implementation

You can verify this works with a quick test:

// Test with sample text
const testPassword = "MySecurePassword123";
const encrypted = encryptText(testPassword);
console.log("Encrypted:", encrypted);
const decrypted = decryptText(encrypted);
console.log("Decrypted:", decrypted); // Should output "MySecurePassword123"

Key Notes to Ensure Compatibility

  • Encoding Consistency: We strictly use ASCII for IV/salt and UTF8 for plaintext, just like your C# code—changing these will break compatibility.
  • PBKDF1 Accuracy: The custom passwordDeriveBytes function exactly mimics C#'s behavior, including generating extra bytes when the key length exceeds SHA1's output.
  • AES Parameters: Node.js uses PKCS7 padding by default, which matches C#'s RijndaelManaged default padding. Don't change this unless your C# code uses a different padding scheme.
  • Iteration Count: Keep passwordIterations set to 2—any change will generate a different key, making decryption fail between Node.js and C#.

内容的提问来源于stack exchange,提问作者Majedur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:28:32