簡體   English   中英

C# 和 Cryptojs 的 TripleDESCryptoServiceProvider 給出不同的結果

[英]TripleDESCryptoServiceProvider for C# and Cryptojs gives different results

為什么我在使用 c# 和 JavaScript cryptojs 對 TriplesDes 進行加密時會得到不同的結果? 請在下面查看我的代碼。

c#

public static string EncryptTxt()
{
    SHA512CryptoServiceProvider sha = new SHA512CryptoServiceProvider();

    using (var tdes = new TripleDESCryptoServiceProvider())
    {
        var msg = 'jvofs:JCV XXXXX:201911141547:12345678';
        var key = 'jjvofs';
        var keyOffset = 10;
        
        System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
        TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

        byte[] Results;
        byte[] newKeyx = new byte[24];

        byte[] keybyte = sha.ComputeHash(Encoding.UTF8.GetBytes(key));
        
        Array.Copy(keybyte, keyOffset, newKeyx, 0, newKeyx.Length);

        TDESAlgorithm.Key = newKeyx;
        TDESAlgorithm.Mode = CipherMode.ECB;
        TDESAlgorithm.Padding = PaddingMode.PKCS7;
        byte[] DataToEncrypt = UTF8.GetBytes(msg);
        try
        {
            ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();
            Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
        }
        finally
        {
            TDESAlgorithm.Clear();
        }
        var a = Convert.ToBase64String(DataToEncrypt);
        var b = Convert.ToBase64String(newKeyx);
        var c = Convert.ToBase64String(Results);
        return Convert.ToBase64String(Results);
    }
}

JavaScript 使用cryptojs

txtEncrypter = () => {
    const msg = 'jvofs:JCV XXXXX:201911141547:12345678';
    const key = 'jjvofs';
    const keyOffset = 10;
    const keybyte: any = this.wordArrayToByteArray(crypto.SHA512(key), 100);

    // For message
    const dataToEncrypt = crypto.enc.Utf8.parse(msg);
    const dte = this.wordArrayToByteArray(dataToEncrypt, 100);
    const dataToEncryptx = this._arrayBufferToBase64(dte);
    const dataToEncryptxx = crypto.enc.Utf8.parse(dataToEncryptx);

    // For key
    let newKeyx = keybyte.slice(keyOffset, 34);
    const newKeyxB4Splice = newKeyx;
    const newKeyxB4Splicex = this._arrayBufferToBase64(newKeyx);
    newKeyx = crypto.enc.Utf8.parse(newKeyx);
    
    const options = {
      mode: crypto.mode.ECB,
      padding: crypto.pad.Pkcs7
    };
    
    const encrypted = crypto.TripleDES.encrypt(dataToEncrypt, newKeyx, options);
    const base64String = encrypted.toString();
    console.log(base64String);
  }



wordArrayToByteArray(wordArray, length) {
    if (wordArray.hasOwnProperty('sigBytes') && wordArray.hasOwnProperty('words')) {
      length = wordArray.sigBytes;
      wordArray = wordArray.words;
    }

    const result = [];
    let bytes: any;
    let i = 0;
    while (length > 0) {
      bytes = this.wordToByteArray(wordArray[i], Math.min(4, length));
      length -= bytes.length;
      result.push(bytes);
      i++;
    }
    return [].concat.apply([], result);
  }

  wordToByteArray(word: any, length: any) {
    const ba = [], xFF = 0xFF;
    if (length > 0) {
      // tslint:disable-next-line:no-bitwise
      ba.push(word >>> 24);
    }
    if (length > 1) {
      // tslint:disable-next-line:no-bitwise
      ba.push((word >>> 16) & xFF);
    }
    if (length > 2) {
      // tslint:disable-next-line:no-bitwise
      ba.push((word >>> 8) & xFF);
    }
    if (length > 3) {
      // tslint:disable-next-line:no-bitwise
      ba.push(word & xFF);
    }
    return ba;
  }

  byteArrayToWordArray(ba) {
    const wa = [];
    let i = 0;
    for (i = 0; i < ba.length; i++) {
      // tslint:disable-next-line:no-bitwise
      wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i);
    }

    return crypto.lib.WordArray.create(wa);
  }

  toUTF8Array(str) {
    const utf8 = [];
    for (let i = 0; i < str.length; i++) {
        let charcode = str.charCodeAt(i);
        if (charcode < 0x80) { utf8.push(charcode); } else if (charcode < 0x800) {
            // tslint:disable-next-line:no-bitwise
            utf8.push(0xc0 | (charcode >> 6), 
                      // tslint:disable-next-line: no-bitwise
                      0x80 | (charcode & 0x3f));
        } else if (charcode < 0xd800 || charcode >= 0xe000) {
            // tslint:disable-next-line: no-bitwise
            utf8.push(0xe0 | (charcode >> 12), 
                      // tslint:disable-next-line: no-bitwise
                      0x80 | ((charcode>>6) & 0x3f), 
                      // tslint:disable-next-line: no-bitwise
                      0x80 | (charcode & 0x3f));
        } else {
            i++;
            // UTF-16 encodes 0x10000-0x10FFFF by
            // subtracting 0x10000 and splitting the
            // 20 bits of 0x0-0xFFFFF into two halves
            // tslint:disable-next-line:no-bitwise
            charcode = 0x10000 + (((charcode & 0x3ff)<<10)
                      // tslint:disable-next-line:no-bitwise
                      | (str.charCodeAt(i) & 0x3ff));
            // tslint:disable-next-line:no-bitwise
            utf8.push(0xf0 | (charcode >>18), 
                      // tslint:disable-next-line:no-bitwise
                      0x80 | ((charcode>>12) & 0x3f), 
                      // tslint:disable-next-line: no-bitwise
                      0x80 | ((charcode>>6) & 0x3f), 
                      // tslint:disable-next-line: no-bitwise
                      0x80 | (charcode & 0x3f));
        }
    }
    return utf8;
}

 _arrayBufferToBase64( buffer ) {
  let binary = '';
  const bytes = new Uint8Array( buffer );
  const len = bytes.byteLength;
  for (let i = 0; i < len; i++) {
      binary += String.fromCharCode( bytes[ i ] );
  }
  return window.btoa( binary );
}

在解析消息和密鑰的數據時,c# 和 JavaScript 是相同的:

信息:

[C#] anZvZnM6SkNWIFhYWFhYOjIwMTkxMTE0MTU0NzoxMjM0NTY3OA==

[cryptojs] anZvZnM6SkNWIFhYWFhYOjIwMTkxMTE0MTU0NzoxMjM0NTY3OA==

鑰匙:

[C#] smbkkmDrCBdRev7S4hLaWE16Nvym+9gW

[cryptojs] smbkkmDrCBdRev7S4hLaWE16Nvym+9gW

但是一旦“crypto.TripleDES.encrypt(....)”運行,我會得到 c# 和 javascript 的不同結果:

[C#] 1pjvBOB81iAOqsskZ+cM080yDU37XBoCwMhbYULwva/Nql5vbEMiPQ==

[cryptojs] ncCcCYNy3jVsB/95SaC2N1rH5Q+hX04WvScMvwmtkPkrnL7Ki1bmPg==

在從 hash 的字節數組中確定鍵作為子數組(包括索引 10 到不包括索引 34)后,必須將該子數組轉換回具有等效內容的WordArray ,即行:

newKeyx = crypto.enc.Utf8.parse(newKeyx);

必須替換為:

newKeyx = byteArrayToWordArray(newKeyx);  

通過此更改,NodeJS 代碼返回與 C# 代碼相同的結果。


轉換WordArray <-> byte-array (以及因此這些轉換所需的所有函數)並不是真正必要的,因為作為替代方案,也可以僅使用CryptoJS-encoders導出密鑰:

...
const key = 'jjvofs';
const keyOffset = 10;
const keyLength = 24;
const keyHash = crypto.enc.Hex.stringify(crypto.SHA512(key));
const newKey = crypto.enc.Hex.parse(keyHash.slice(keyOffset * 2, (keyOffset + keyLength) * 2));
...

順便說一句: ECB模式是不安全的,應該使用性能更高的 AES 來代替TripleDES

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM