如何将padbytes函数转换为ColdFusion

3

我有以下Node.js代码,现在我想转换成ColdFusion代码:

// a correct implementation of PKCS7. The rijndael js has a PKCS7 padding already implemented
// however, it incorrectly pads expecting the phrase to be multiples of 32 bytes when it should pad based on multiples
// 16 bytes. Also, every javascript implementation of PKCS7 assumes utf-8 char encoding. C# however is unicode or utf-16.
// This means that chars need to be treated in our code as 2 byte chars and not 1 byte chars.
function padBytes(string){
  const strArray = [...new Buffer(string, 'ucs2')];

  const need = 16 - ((strArray.length) % 16);
  for(let i = 0; i < need; i++) {
    strArray.push(need);
  }

  return Buffer.from(strArray);
}

我正在尝试理解这个函数的确切作用并将其转换。我的理解是,它将字符串转换为UTF-16(UCS2),然后为每个字符添加填充。但是,我不明白为什么变量 need 的值是它的值,也不知道在CF中如何实现这一点。
我也不明白为什么它只会一遍又一遍地将同一个值推入数组。首先,在我的示例脚本中,字符串是2018-06-14T15:44:10Z testaccount。字符串数组长度为64。我不确定如何在CF中实现甚至那样。
我已经尝试了字符编码,将其转换为二进制和UTF-16,并且只是不太理解js函数以在ColdFusion中复制它。我觉得我在编码方面缺少了些东西。
编辑:
所选答案解决了这个问题,但因为我最终要使用输入数据进行加密,更简单的方法是根本不使用此函数而执行以下操作:
<cfset stringToEncrypt = charsetDecode(input,"utf-16le") />
<cfset variables.result = EncryptBinary(stringToEncrypt, theKey, theAlgorithm, theIV) />
1个回答

1

更新:

我们在聊天中进行了跟进,结果发现该值最终与encrypt()一起使用。由于encrypt()已经自动处理了填充,因此不需要使用自定义的padBytes()函数。但是,它确实需要切换到不太常用的encryptBinary()函数以保持UTF-16编码。常规的encrypt()函数只处理UTF-8,这会产生完全不同的结果。

Trycf.com示例:

// Result with sample key/iv: P22lWwtD8pDrNdQGRb2T/w==
result = encrypt("abc", theKey, theAlgorithm, theEncoding, theIV); 

// Result Result with sample key/iv: LJCROj8trkXVq1Q8SQNrbA== 
input = charsetDecode("abc", "utf-16le");
result= binaryEncode(encryptBinary(input, theKey, theAlgorithm, theIV), "base64);

它正在将字符串转换为UTF-16(UCS2),然后对每个字符添加填充。......我觉得编码方面可能有些遗漏。
是的,第一部分似乎将字符串解码为UTF-16(或UCS2,它们略有不同)。至于您错过了什么,您并不是唯一的。在找到解释“UTF-16”会添加BOM的this comment之前,我也无法使其正常工作。要省略BOM,请使用所需字节顺序的“UTF-16BE”或“UTF-16LE”。
为什么它只重复推送相同的值到数组中?

因为这就是PCKS7填充的定义。它不使用像空值或零值这样的填充,而是计算需要多少字节的填充。然后使用该数字作为填充值。例如,假设一个字符串需要额外的三个字节的填充。PCKS7会附加值3 - 三次:"string" + "3" + "3" + "3"

CF中的其余代码类似。不幸的是,charsetDecode()的结果是不可变的。您必须构建一个单独的数组来保存填充,然后将两者组合起来。

注意,此示例使用CF2016特定语法来组合数组,但也可以使用简单的循环来完成

函数:

function padBytes(string text){

  var combined = [];
  var padding = [];
  // decode as utf-16
  var decoded = charsetDecode(arguments.text,"utf-16le");

  // how many padding bytes are needed?
  var need = 16 - (arrayLen(decoded) % 16);
  // fill array with any padding bytes
  for(var i = 0; i < need; i++) {
     padding.append(need);
  }

  // concatenate the two arrays
  // CF2016+ specific syntax. For earlier versions, use a loop 
  combined = combined.append(decoded, true);
  combined = combined.append(padding, true);

  return combined;
}

使用方法:

result = padBytes("2018-06-14T15:44:10Z testaccount");
writeDump(binaryEncode( javacast("byte[]", result), "base64"));

明天迫不及待地想要检查这个。谢谢。它是一个更大的加密项目的一部分,希望它能够正常工作。我会让你知道进展情况的。 - Leeish
其实,我不确定它是否完全正确。今天稍后再看一下。它可以处理ASCII字符,但是对于更奇特的字符存在一些差异,我还不确定原因... - SOS
我仍然没有得到相同的结果……我想是因为以下原因。如果我输出strArray的值,它看起来像这样 2 0 1 8 - 0 6 - 1 4 T..... 数组的长度为76,基本上显示了那些空格。我之前尝试添加每个字母之间的charsetEncode(javacast("byte[]", [0]), "utf-8"),但即使现在使用utf-16le,字符串的长度也不匹配节点。 - Leeish
你是说示例值“2018-06-14T15:44:10Z testaccount”不匹配吗?当我检查base64编码输出时,它与node和CF2016相同。尽管如此,我不确定对于更奇特的字符是否仍然成立。 - SOS
你的输出只有CF16吗?我在我的服务器上运行相同的代码,但是在binaryEncode输出的末尾,我得到了The value [B cannot be converted to a number.的错误。但是,是的,base64的结果与我需要的匹配。请参见我的函数padbytes2。它产生了相同的结果,但我无法在我的服务器上运行binaryencode(javacast(.... - Leeish
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接