AES-CTR在Go中加密并在CryptoJS

时间:2016-04-28 08:52:13

标签: javascript encryption go cryptography cryptojs

我在使用CryptoJS解密使用Go lang加密的文本时遇到问题。

这是Go代码: https://play.golang.org/p/xCbl48T_iN

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "fmt"
)

func main() {
    key := []byte("1234567890123456")
    plaintext := []byte("text can be a random lenght")

    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }

    // The IV needs to be unique, but not secure. Therefore it's common to
    // include it at the beginning of the ciphertext.
    // BTW (only for test purpose) I don't include it

    ciphertext := make([]byte, len(plaintext))

    iv := []byte{'\x0f','\x0f','\x0f','\x0f','\x0f','\x0f','\x0f','\x0f','\x0f','\x0f','\x0f','\x0f','\x0f','\x0f','\x0f','\x0f'}

    stream := cipher.NewCTR(block, iv)
    stream.XORKeyStream(ciphertext, plaintext) 

    // CTR mode is the same for both encryption and decryption, so we can
    // also decrypt that ciphertext with NewCTR.
        base := base64.StdEncoding.EncodeToString(ciphertext)
    fmt.Printf("encodedHEX: %x\n", ciphertext)
    fmt.Printf("encodedBASE: %s\n", base)

    plaintext2 := make([]byte, len(plaintext))
    stream = cipher.NewCTR(block, iv)
    stream.XORKeyStream(plaintext2, ciphertext)

    fmt.Printf("decoded: %s\n", plaintext2)
}

这是JS代码: http://jsfiddle.net/Ltkxm64n/

var key = CryptoJS.enc.Hex.parse('31323334353637383930313233343536');
var iv = CryptoJS.enc.Hex.parse('0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f');
var encrypted = CryptoJS.AES.encrypt("text can be a random lenght", key, {
  mode: CryptoJS.mode.CTR,
  iv: iv
});

console.log(encrypted.ciphertext.toString());
console.log(encrypted.toString());

var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
  mode: CryptoJS.mode.CTR,
  iv: iv
});
console.log(decrypted.toString(CryptoJS.enc.Utf8)); 
// text can be a random lenght

两者都可以很好地加密和解密,但是当我将base64密文从GO复制到JS(或者反之亦然)时,它并不起作用。 我还注意到js输出的第一部分与Go输出相同,但在js输出中,字节数比Go中的多。

我的目的是加密GO中的一些文本,然后将Base64密文发送给可以解密它的JS。

谢谢

2 个答案:

答案 0 :(得分:5)

好的,这是你要解决的问题:

  1. 在您的来源列表中添加无填充js:http://crypto-js.googlecode.com/svn/tags/3.1/build/components/pad-nopadding.js

  2. 加密/解密时指定参数:padding: CryptoJS.pad.NoPadding

  3. CTR模式在加密前不需要填充纯文本。
    在XORing之前,修剪从多个AES块生成的密钥流以匹配纯文本长度 看起来CryptoJS使用纯文本为xor生成密钥流,但不修剪它,因为CryptoJS生成的密文长度不是padding: CryptoJS.pad.NoPadding总是16字节的倍数(与AES块大小完全相同) )。

    
    
    var key = CryptoJS.enc.Hex.parse('31323334353637383930313233343536');
    var iv = CryptoJS.enc.Hex.parse('0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f');
    var encrypted = CryptoJS.AES.encrypt("text can be a random lenght", key, {
      mode: CryptoJS.mode.CTR,
      iv: iv,
      padding: CryptoJS.pad.NoPadding
    });
    
    document.getElementById("id").innerHTML = encrypted.ciphertext.toString();
    document.getElementById("id2").innerHTML = encrypted.toString();
    
    var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
      mode: CryptoJS.mode.CTR,
      iv: iv,
      padding: CryptoJS.pad.NoPadding
    });
    document.getElementById("decrypt").innerHTML = decrypted.toString(CryptoJS.enc.Utf8); // text can be a random lenght
    
    <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
    <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/mode-ctr.js"></script>
    <script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/components/pad-nopadding.js"></script>
    <p> Ciphertext in HEX: </p>
    <p id="id"> </p>
    <p> Ciphertext in BASE64: </p>
    <p id="id2"> </p>
    <p> PlainText: </p>
    <p id="decrypt"></p>
    &#13;
    &#13;
    &#13;

答案 1 :(得分:0)

在编码之前你必须在明文中添加填充

例如:

func addPadding(data []byte, blocksize int) []byte {

    padSize := len(data) % blocksize
    if padSize == 0 {
        return data
    }
    padSize = blocksize - padSize
    return append(data, bytes.Repeat([]byte{byte(padSize)}, padSize)...)
}
//in main
    plaintext := []byte("text can be a random lenght")
    plaintext = addPadding(plaintext, aes.BlockSize)