R实现ECB AES-128不兼容?



我对加密非常陌生,所以我试图重新创建一个简单的欧洲央行AES-128加密,如这个在线工具所示:https://www.devglan.com/online-tools/aes-encryption-decryption

但是,当尝试加密明文时:

"parameter1 = 1, parameter2 = 2, par3 = 3">

使用key:

"1234567890123456">

我从digest R实现和上述站点得到不同的结果。也就是R给出了十六进制的结果:

00 63 2a 41 0a 39 0a ab b7 b9 80 b8 f1 4b 07 d9 a7 20 94 d6 b0 5b 57 17 67 68 36 a2 70 ca a2 8f">

而在线工具显示:

"00 63 2A 41 0A 39 0A AB B7 B9 80 B8 F1 4B 07 D9 1B 09 5D 83 76 9F 6B 47 7E 51 FA D9 99 56 CE 2C B7 5A 26 54 C9 F3 6F EC 36 EF B5 D6 D2 1D 2C 0 ">

有趣的是,前16个字节是相同的,但之后就不同了。

代码如下:


Test_String <- paste("parameter1=1", "parameter2=2", "par3=3", sep = "&")
Passphrase <- charToRaw("1234567890123456")
ECB_AES <- AES(key = Passphrase , mode = "ECB")
(Encrypted_Test_String <- ECB_AES$encrypt(Test_String))

UPDATE:我通过添加padding参数实现了对digest::AES()的填充支持。默认情况下,它是关闭向后兼容性的,所以你需要将padding=TRUE添加到AES()调用中。它现在是在CRAN版本0.6.32。


如果使用不支持填充的旧版本{digest}(2023-06-26之前):

要对@PaulEagle的答案进行扩展,这里有一个函数,它接受一个明文字符串并将其转换为带填充的原始向量:

pad <- function(plaintext) {
block_length <- 16
bytes_to_pad <- block_length - (nchar(plaintext) %% block_length)
padded_raw <- c(charToRaw(plaintext), rep(as.raw(bytes_to_pad), times = bytes_to_pad))
padded_raw
}

Paul回答中提供的原始功能对我不起作用,所以我不得不稍微修改一下。例如:

test <- "parameter1=1&parameter2=2&parameter3=3&par4=4"
pad(test)

生产

70 61 72 61 6d 65 74 65 72 31 3d 31 26 70 61 72 61 6d 65 74 65 72 32 3d 32 26 70 61 72 61 6d 65 74 65 72 33 3d 33 26 70 61 72 34 3d 34 03 03 03

还要注意,如果你使用" ccb"或";CTR"模式,那么{openssl}包应该工作,因为它会自动处理填充,但它没有"ECB"模式。

以防万一有人再次需要这个,这是我想出的解决方案,感谢@Topaco的提示。

问题确实在于,默认情况下,digest::AES()不会填充原始转换的纯文本。

在我最初的帖子中引用的在线工具,以及大多数在线工具,都使用PKCS7,它用空白长度的字节表示填充空白到块长度(16字节),或者如果块长度完全对齐,则填充16。

示例:纯文本"parameter1=1&parameter2=2&parameter3=3&par4=4"原始转换
Test_String <- "parameter1=1&parameter2=2&parameter3=3&par4=4"
Raw_Test_String <- charToRaw(Test_String)

的长度为45 (70 61 72 61 6d 65 74 65 72 31 3d 31 26 70 61 72 61 6d 65 74 65 72 32 3d 32 26 70 61 72 61 6d 65 74 65 72 33 3d 33 26)70 61 72 34 3d 34),所以到块长度16(16 * 3 = 48)的间隙是3。因此,字符串必须在字节表示(03)中填充3个3。charToRaw在这里不起作用,所以我们需要使用as.raw(3)来获得所需的字节表示。

Raw_Padded_String <- c(Raw_Test_String, c(as.raw(3),as.raw(3),as.raw(3)))

,然后在解密后产生与在线工具相同的输出:

Passphrase <- charToRaw("1234567890123456")
ECB_AES <- AES(key = Passphrase , mode = "ECB")
(Encrypted_Test_String <- ECB_AES$encrypt(Raw_Padded_String))

由于没有函数可以对我能找到的任何字符串长度的重复过程执行此操作,这里有一个以防有人需要它:

PKCS7 <- function(Raw_Text, block_length = 16){

bytes_to_padd <- (ceiling((length(Raw_Text) / block_length)) - (nchar(Raw_Text) / block_length)) * block_length

if(bytes_to_padd == 0) bytes_to_padd <- 16

Padded_Raw_Text <- c(Raw_Text, rep(as.raw(bytes_to_padd), times = bytes_to_padd))
return(Padded_Raw_Text)

}

我知道这不是理想的,但它对我很有效。

在您的在线工具中,可用的密钥大小为128、196和256位。

如果您查看ECB_AES,它会告诉您R中的密钥大小为16

> ECB_AES
AES cipher object; mode ECB key size 16 

最新更新