R将包含反斜杠的字符串从文件传递给charToRaw而不转义
R pass a string containing backslashes from a file to charToRaw without escaping
我正在尝试从受密码保护的文件中将数据库的密钥读入 R 并将其转换为原始文件,如下所示:
假设我的密钥是\xb@\xErd\xD5b\x1bs
。我的目标是获得与将密钥作为字符串直接传递给 charToRaw
函数时得到的相同的原始密钥:
rawkey1 <- charToRaw("\xb@\xErd\xD5b\x1bs")
> rawkey1
[1] 0b 40 0e 72 64 d5 62 1b 73
我可以将其保存在 .csv 文件中并将其读回 R:
savemykey <- data.table(keyinbytes = "\xb@\xErd\xD5b\x1bs")
write.csv(savemykey, file = "My_key.csv")
mykey <- read.csv("My_key.csv", header = TRUE, stringsAsFactors = FALSE)
然后我可以将其转换为原始格式并产生所需的结果:
> rawkey2 = charToRaw(mykey$keyinbytes)
> rawkey2
[1] 0b 40 0e 72 64 d5 62 1b 73
直接传递给 charToRaw
函数和读取包含密钥的 csv 文件生成的原始密钥是相同的:
> rawkey1 == rawkey2
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
到目前为止一切顺利。唯一的问题是密钥是包含敏感信息的数据库的密钥,因此我想将其存储在受密码保护的文件中。
我能想到的唯一方法是使用 Microsoft Excel(使用 excel.link 包重新读取并提供密码作为参数);然而,似乎在创建 .xlsx 文件时,反斜杠在读回时被解释为转义符。这导致从字符到原始的错误转换:
library(xlsx)
write.xlsx2(savemykey, file = "My_key.xlsx", append = FALSE)
然后我打开 Microsoft Excel 文件,分配密码 "mypassword",保存并用 excel.link 包读回:
library(excel.link)
mykey <- xl.read.file("My_key.xlsx", xl.sheet = 1, password = "mypassword")
# Re-running the conversion:
rawkey3 = charToRaw(mykey$keyinbytes)
> rawkey3
[1] 3f 40 3f 72 64 d5 62 3f 73
如果我将此结果与第一个键进行比较,它不匹配:
> rawkey3 == rawkey1
[1] FALSE TRUE FALSE TRUE TRUE TRUE TRUE FALSE TRUE
这是因为在读取 Microsoft Excel 文件时,R 已将反斜杠解释为转义符,将其后的字符转义并替换为 '?',见下文:
# Key as assigned object in R:
> savemykey$keyinbytes
[1] "\v@6rdÕb3s"
# Key read in from Microsoft Excel file:
> mykey$keyinbytes
[1] "?@?rdÕb?s"
根据我目前的尝试,似乎如果我将密钥保存在任何可以保存为纯文本(.csv、.txt 或直接在 R 脚本中并获取它的文件类型中),通过对反斜杠的正确评估将密钥读回 R,并转换为原始字节的正确模式。但是,我一直找不到任何密码保护纯文本文件/.csv 或 R 脚本的方法。
我想:
找到一种密码保护纯文本格式文件的方法,在读回 R 时保留对密钥中反斜杠的评估,并且读入方法将密码作为参数,或;
找到一种方法从受密码保护的 Microsoft Excel 文件中读取密钥,而不对反斜杠进行转义。
任何有关如何执行此操作的想法都将不胜感激。
我确实找到了一种创建加密文本文件的方法(可以是数据,也可以是稍作修改的 R 脚本)。 Stephane Doyen 在这里创建了一个脚本,用于创建一个加密文件,然后在使用摘要包读回后解密它:https://github.com/sdoyen/r_password_crypt .
工作原理如下:
# Load libraries
# This does the encryption and decryption
require(digest)
# This allows users to enter a password securely with a masked widget
require(getPass)
# I'll put the details I want to encrypt into a data.table
require(data.table)
创建并输入密码(长度必须是 16 个字母数字字符的倍数,例如 'myfavouritepw123'):
mypw <- charToRaw(getPass("Enter the password for your login details file:"))
加载 Stephane 的 write.aes 和 read.aes 函数:
# To encrypt and password protect a file:
write.aes <- function(df,filename, key) {
require(digest)
zz <- textConnection("out","w")
write.csv(df,zz, row.names=F)
close(zz)
out <- paste(out,collapse="\n")
raw <- charToRaw(out)
raw <- c(raw,as.raw(rep(0,16-length(raw)%%16)))
aes <- AES(key,mode="ECB")
aes$encrypt(raw)
writeBin(aes$encrypt(raw),filename)
}
# To decrypt the file with a password after reading it back in:
read.aes <- function(filename,key) {
require(digest)
dat <- readBin(filename,"raw",n=1000)
aes <- AES(key,mode="ECB")
raw <- aes$decrypt(dat, raw=TRUE)
txt <- rawToChar(raw[raw>0])
read.csv(text=txt, stringsAsFactors = F)
}
创建您要加密的文件:
注意:使用 write.aes
加密将导致“\”及其前面的字符被误解。为避免这种情况,将密钥转换为原始并将原始字节保存为单个字符串。使用 paste0
和 collapse
将表示每个字节的字符粘贴在一起(sep
不起作用)。
mysecretlogin1 <- data.table(keyinbytes = paste0(charToRaw("\xb@\xErd\xD5b\x1bs"), collapse = " "))
将 data.table 写入加密文件 write.aes 使用您之前创建的密码作为密钥:
write.aes(df = mysecretlogin1, filename = "mysecretkey.txt", key = mypw)
读回文件并用您的密码解密:
mypw <- charToRaw(getPass("Enter the password for your login details file:"))
mysecretlogin2 <- data.table(read.aes(filename = "mysecretkey.txt", key = mypw))
检查导出和导入的文件是否相同:
> mysecretlogin1 == mysecretlogin2
keyinbytes
[1,] TRUE
要以原始形式使用密钥,可以使用此函数将字符串转换回原始字节(在每个字节前添加“0x”允许将它们作为原始向量传递给不带引号的列表) :
makeraw <- function(characterstring) {
mystring <- strsplit(characterstring, " ")
mystring <- lapply(mystring, function(x) paste0("0x", x))
mystring <- as.raw(unlist(mystring))
mystring
}
应用函数:
myrawkey <- makeraw(mysecretlogin2$keyinbytes)
检查它是否有效:
> myrawkey
[1] 0b 40 0e 72 64 d5 62 1b 73
> str(myrawkey)
raw [1:9] 0b 40 0e 72 ...
> is.raw(myrawkey)
[1] TRUE
此解决方案中的 'key'(没有双关语!)通过将密钥存储为(漂亮的字母数字)原始字节的字符串版本来避免将反斜杠误解为转义字符的整个问题。
我正在尝试从受密码保护的文件中将数据库的密钥读入 R 并将其转换为原始文件,如下所示:
假设我的密钥是\xb@\xErd\xD5b\x1bs
。我的目标是获得与将密钥作为字符串直接传递给 charToRaw
函数时得到的相同的原始密钥:
rawkey1 <- charToRaw("\xb@\xErd\xD5b\x1bs")
> rawkey1
[1] 0b 40 0e 72 64 d5 62 1b 73
我可以将其保存在 .csv 文件中并将其读回 R:
savemykey <- data.table(keyinbytes = "\xb@\xErd\xD5b\x1bs")
write.csv(savemykey, file = "My_key.csv")
mykey <- read.csv("My_key.csv", header = TRUE, stringsAsFactors = FALSE)
然后我可以将其转换为原始格式并产生所需的结果:
> rawkey2 = charToRaw(mykey$keyinbytes)
> rawkey2
[1] 0b 40 0e 72 64 d5 62 1b 73
直接传递给 charToRaw
函数和读取包含密钥的 csv 文件生成的原始密钥是相同的:
> rawkey1 == rawkey2
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
到目前为止一切顺利。唯一的问题是密钥是包含敏感信息的数据库的密钥,因此我想将其存储在受密码保护的文件中。
我能想到的唯一方法是使用 Microsoft Excel(使用 excel.link 包重新读取并提供密码作为参数);然而,似乎在创建 .xlsx 文件时,反斜杠在读回时被解释为转义符。这导致从字符到原始的错误转换:
library(xlsx)
write.xlsx2(savemykey, file = "My_key.xlsx", append = FALSE)
然后我打开 Microsoft Excel 文件,分配密码 "mypassword",保存并用 excel.link 包读回:
library(excel.link)
mykey <- xl.read.file("My_key.xlsx", xl.sheet = 1, password = "mypassword")
# Re-running the conversion:
rawkey3 = charToRaw(mykey$keyinbytes)
> rawkey3
[1] 3f 40 3f 72 64 d5 62 3f 73
如果我将此结果与第一个键进行比较,它不匹配:
> rawkey3 == rawkey1
[1] FALSE TRUE FALSE TRUE TRUE TRUE TRUE FALSE TRUE
这是因为在读取 Microsoft Excel 文件时,R 已将反斜杠解释为转义符,将其后的字符转义并替换为 '?',见下文:
# Key as assigned object in R:
> savemykey$keyinbytes
[1] "\v@6rdÕb3s"
# Key read in from Microsoft Excel file:
> mykey$keyinbytes
[1] "?@?rdÕb?s"
根据我目前的尝试,似乎如果我将密钥保存在任何可以保存为纯文本(.csv、.txt 或直接在 R 脚本中并获取它的文件类型中),通过对反斜杠的正确评估将密钥读回 R,并转换为原始字节的正确模式。但是,我一直找不到任何密码保护纯文本文件/.csv 或 R 脚本的方法。
我想:
找到一种密码保护纯文本格式文件的方法,在读回 R 时保留对密钥中反斜杠的评估,并且读入方法将密码作为参数,或;
找到一种方法从受密码保护的 Microsoft Excel 文件中读取密钥,而不对反斜杠进行转义。
任何有关如何执行此操作的想法都将不胜感激。
我确实找到了一种创建加密文本文件的方法(可以是数据,也可以是稍作修改的 R 脚本)。 Stephane Doyen 在这里创建了一个脚本,用于创建一个加密文件,然后在使用摘要包读回后解密它:https://github.com/sdoyen/r_password_crypt .
工作原理如下:
# Load libraries
# This does the encryption and decryption
require(digest)
# This allows users to enter a password securely with a masked widget
require(getPass)
# I'll put the details I want to encrypt into a data.table
require(data.table)
创建并输入密码(长度必须是 16 个字母数字字符的倍数,例如 'myfavouritepw123'):
mypw <- charToRaw(getPass("Enter the password for your login details file:"))
加载 Stephane 的 write.aes 和 read.aes 函数:
# To encrypt and password protect a file:
write.aes <- function(df,filename, key) {
require(digest)
zz <- textConnection("out","w")
write.csv(df,zz, row.names=F)
close(zz)
out <- paste(out,collapse="\n")
raw <- charToRaw(out)
raw <- c(raw,as.raw(rep(0,16-length(raw)%%16)))
aes <- AES(key,mode="ECB")
aes$encrypt(raw)
writeBin(aes$encrypt(raw),filename)
}
# To decrypt the file with a password after reading it back in:
read.aes <- function(filename,key) {
require(digest)
dat <- readBin(filename,"raw",n=1000)
aes <- AES(key,mode="ECB")
raw <- aes$decrypt(dat, raw=TRUE)
txt <- rawToChar(raw[raw>0])
read.csv(text=txt, stringsAsFactors = F)
}
创建您要加密的文件:
注意:使用 write.aes
加密将导致“\”及其前面的字符被误解。为避免这种情况,将密钥转换为原始并将原始字节保存为单个字符串。使用 paste0
和 collapse
将表示每个字节的字符粘贴在一起(sep
不起作用)。
mysecretlogin1 <- data.table(keyinbytes = paste0(charToRaw("\xb@\xErd\xD5b\x1bs"), collapse = " "))
将 data.table 写入加密文件 write.aes 使用您之前创建的密码作为密钥:
write.aes(df = mysecretlogin1, filename = "mysecretkey.txt", key = mypw)
读回文件并用您的密码解密:
mypw <- charToRaw(getPass("Enter the password for your login details file:"))
mysecretlogin2 <- data.table(read.aes(filename = "mysecretkey.txt", key = mypw))
检查导出和导入的文件是否相同:
> mysecretlogin1 == mysecretlogin2
keyinbytes
[1,] TRUE
要以原始形式使用密钥,可以使用此函数将字符串转换回原始字节(在每个字节前添加“0x”允许将它们作为原始向量传递给不带引号的列表) :
makeraw <- function(characterstring) {
mystring <- strsplit(characterstring, " ")
mystring <- lapply(mystring, function(x) paste0("0x", x))
mystring <- as.raw(unlist(mystring))
mystring
}
应用函数:
myrawkey <- makeraw(mysecretlogin2$keyinbytes)
检查它是否有效:
> myrawkey
[1] 0b 40 0e 72 64 d5 62 1b 73
> str(myrawkey)
raw [1:9] 0b 40 0e 72 ...
> is.raw(myrawkey)
[1] TRUE
此解决方案中的 'key'(没有双关语!)通过将密钥存储为(漂亮的字母数字)原始字节的字符串版本来避免将反斜杠误解为转义字符的整个问题。