【问题标题】:R pass a string containing backslashes from a file to charToRaw without escapingR将包含反斜杠的字符串从文件传递给charToRaw而不转义
【发布时间】:2017-03-02 21:58:30
【问题描述】:

我正在尝试从受密码保护的文件中将数据库的密钥读入 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)

然后我可以将其转换为 raw 并产生所需的结果:

> 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@\016rdÕb\033s"

# Key read in from Microsoft Excel file:
> mykey$keyinbytes
[1] "?@?rdÕb?s"

根据我迄今为止的尝试,似乎如果我将密钥保存在任何可以保存为纯文本的文件类型(.csv、.txt 或直接保存在 R 脚本中并获取它),通过正确评估反斜杠将密钥读回 R 并转换为正确的原始字节模式。但是,我一直找不到任何方法来保护纯文本文件/.csv 或 R 脚本的密码。

我愿意:

  • 找到一种密码保护纯文本格式文件的方法,该方法在读回 R 时保留对密钥中反斜杠的评估,并且读入方法将密码作为参数,或者;

  • 想办法从受密码保护的 Microsoft Excel 文件中读取密钥,而不会转义反斜杠。

任何关于如何做到这一点的想法将不胜感激。

【问题讨论】:

  • 我在 Windows 7 操作系统中使用(64 位)R 3.3.2 和 RStudio 1.0.136。我认为我的 Microsoft Office 程序可能是 32 位的,因为在查询 MS Access 数据库时我必须调用 32 位 R(如果有任何相关性)。

标签: r excel escaping key password-protection


【解决方案1】:

我确实找到了一种创建加密文本文件的方法(可以是数据,也可以是稍加修改的 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 加密会导致“\”和它们前面的字符被误解。为避免这种情况,将密钥转换为原始并将原始字节保存为单个字符串。使用paste0collapse 将代表每个字节的字符粘贴在一起(sep 不起作用)。

mysecretlogin1 <- data.table(keyinbytes = paste0(charToRaw("\xb@\xErd\xD5b\x1bs"), collapse = " "))

使用您之前创建的密码作为密钥,使用 write.aes 将 data.table 写入加密文件:

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

此解决方案中的“键”(不是双关语!)通过将键存储为(漂亮的字母数字)原始字节的字符串版本来避免将反斜杠误解为转义字符的整个问题。

【讨论】:

    猜你喜欢
    • 2022-07-21
    • 2014-12-04
    • 1970-01-01
    • 2011-06-08
    • 2021-12-16
    • 2012-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多