如何使用OpenSSL加密/解密文件?

309
我想使用一个密码来加密和解密一个文件。如何使用OpenSSL来实现呢?

3
你应该使用PKCS5_PBKDF2_HMAC从密码中派生出一个密钥和IV。你应该使用EVP_*函数进行加密和解密。请参阅OpenSSL维基上的EVP对称加密和解密。事实上,你应该使用认证加密,因为它提供了机密性和真实性。请参阅OpenSSL维基上的EVP认证加密和解密 - jww
3
从你的问题中无法理解为什么你想要 OpenSSL。下面的评论显示 GPG 更好,也因为其安全性。我投票反对。 - Yaroslav Nikitenko
您可能需要查看“keepout”,以保存与加密文件一起使用的所有加密选项...这在openssl enc的“默认”选项已更改并且将来可能会更改的情况下尤为重要。此外,它还为新的-pbkdf2选项设置了更高和随机的迭代计数。https://antofthy.gitlab.io/software/#keepout - anthony
我无法使用这些代码解密,有人可以帮助我解密我的文件吗?@matthias Braun - undefined
9个回答

349

37
根据现有情况(截至本文写作时),回答可能不是最优选项,具体取决于提问者的使用情况。特别是参数“-a”可能不是最优的,而且回答没有解释其用途。当加密输出以ASCII/文本形式传输时,通常会使用“-a”参数,并增加输出大小与二进制形式相比。原帖作者并未指定输出格式,因此我认为至少应该提到这一点。请参见答案:https://dev59.com/dWQo5IYBdhLWcg3wbe_r#31552829,其中还包括一个有关为什么应该使用gpg而不是openssl执行此任务的说明。 - moo
12
由于没有密钥衍生,不要使用上述命令。在此处阅读更多信息:openssl弱密钥衍生 - Jonas Lejon
1
还应该指定一个键,或者提及它来自哪里。它是否被加强了? - Tuntable
6
根据最新的手册,它声明:“在Openssl 1.1.0中,默认摘要从MD5更改为SHA256。”来源:https://github.com/openssl/openssl/blob/master/doc/man1/enc.pod - Kebman
4
补充@Kebman的评论,如果你计划在另一台机器上使用此文件,可以在编码和解码命令中添加“-md sha256”。这应该可以保证不受OpenSSL版本不兼容/差异的影响。 - dev-rowbot
显示剩余4条评论

266

使用GPG(比OpenSSL更好的选择)

虽然您特别询问了关于OpenSSL的问题(请参见下面的"使用OpenSSL"以获取OpenSSL解决方案),但您可能希望考虑使用GPG来进行加密,根据这篇文章OpenSSL vs GPG for encrypting off-site backups?

要使用GPG执行相同的操作,您可以使用以下命令:

加密:

gpg --output encrypted.data --symmetric --cipher-algo AES256 un_encrypted.data

解密:

gpg --output un_encrypted.data --decrypt encrypted.data

注意:在加密或解密时,系统会提示您输入密码。并且使用--no-symkey-cache标志来禁用缓存。

使用OpenSSL(简短回答)

如上所述,您可能更倾向于使用gpg而不是openssl,但为了回答这个问题,我们将使用openssl

加密:

openssl enc -aes-256-cbc -in un_encrypted.data -out encrypted.data

解密:

openssl enc -d -aes-256-cbc -in encrypted.data -out un_encrypted.data

注意:在加密或解密时,会提示您输入密码。

使用OpenSSL(长篇回答)

关于openssl enc,您最好的信息来源可能是:https://www.openssl.org/docs/man1.1.1/man1/enc.html

命令行: openssl enc的格式如下:

openssl enc -ciphername [-in filename] [-out filename] [-pass arg]
[-e] [-d] [-a/-base64] [-A] [-k password] [-kfile filename] 
[-K key] [-iv IV] [-S salt] [-salt] [-nosalt] [-z] [-md] [-p] [-P] 
[-bufsize number] [-nopad] [-debug] [-none] [-engine id]

关于您的问题,以下是最有用的参数解释:
-e
    Encrypt the input data: this is the default.

-d    
    Decrypt the input data.

-k <password>
    Only use this if you want to pass the password as an argument. 
    Usually you can leave this out and you will be prompted for a 
    password. The password is used to derive the actual key which 
    is used to encrypt your data. Using this parameter is typically
    not considered secure because your password appears in 
    plain-text on the command line and will likely be recorded in 
    bash history.

-kfile <filename>
    Read the password from the first line of <filename> instead of
    from the command line as above.

-a
    base64 process the data. This means that if encryption is taking 
    place the data is base64 encoded after encryption. If decryption 
    is set then the input data is base64 decoded before being 
    decrypted.
    You likely DON'T need to use this. This will likely increase the
    file size for non-text data. Only use this if you need to send 
    data in the form of text format via email etc.

-salt
    To use a salt (randomly generated) when encrypting. You always
    want to use a salt while encrypting. This parameter is actually
    redundant because a salt is used whether you use this or not 
    which is why it was not used in the "Short Answer" above!

-K key    
    The actual key to use: this must be represented as a string
    comprised only of hex digits. If only the key is specified, the
    IV must additionally be specified using the -iv option. When 
    both a key and a password are specified, the key given with the
    -K option will be used and the IV generated from the password 
    will be taken. It probably does not make much sense to specify 
    both key and password.

-iv IV
    The actual IV to use: this must be represented as a string 
    comprised only of hex digits. When only the key is specified 
    using the -K option, the IV must explicitly be defined. When a
    password is being specified using one of the other options, the 
    IV is generated from this password.

-md digest
    Use the specified digest to create the key from the passphrase.
    The default algorithm as of this writing is sha-256. But this 
    has changed over time. It was md5 in the past. So you might want
    to specify this parameter every time to alleviate problems when
    moving your encrypted data from one system to another or when
    updating openssl to a newer version.

16
关于更喜欢 GPG 胜过 OpenSSL 的评论很好。让我感到难以置信的是,OpenSSL 使用一个如此弱的密码派生哈希算法作为密钥! - Mark
5
确保在使用老版本openssl加密的文件中使用"-md md5"选项以确保与其兼容,否则您会发现这些文件在新系统上无法解密:https://github.com/libressl-portable/portable/issues/378 - Sam Liddicott
11
当加密或解密时,系统会提示您输入密码。但是,gpg让我在解密文件时没有被提示输入密码。看起来密码已经被存储了一段时间,这并不是我想要的。 - user76284
3
@user76284 这可能解决您的问题:https://unix.stackexchange.com/a/395876/79875。我认为您正在运行`gpg-agent`。 - moo
4
似乎选项 --no-symkey-cache 会禁用 gpg 在使用 --symmetric 时的缓存功能,即使代理正在运行。 - user76284
显示剩余3条评论

50

加密:

openssl enc -in infile.txt -out encrypted.dat -e -aes256 -k symmetrickey

解密:

openssl enc -in encrypted.dat -out outfile.txt -d -aes256 -k symmetrickey

详情请参见openssl(1)文档。


17
使用明文密码,将-k symmetrickey替换为-pass stdin-pass 'pass:PASSWORD' - Zenexer
6
因为没有密钥派生,所以不要使用上述命令。在此阅读更多信息:openssl弱密钥派生 - Jonas Lejon
8
关于@jonasl的评论,需要注意的是-k symmetrickey是具有误导性的。-k选项用于指定密码,OpenSSL从中派生对称密钥。如果您想要指定对称密钥,则必须使用-K选项。 - user1071847
@Andrii Abramov,我无法使用这些代码解密文件,有没有其他方法可以帮助我解密文件? - undefined

28

不要使用OpenSSL默认的密钥派生方法。

当前被接受的答案使用了它,但它已经不再推荐和安全了。

攻击者非常容易仅仅通过暴力破解密钥。

https://www.ietf.org/rfc/rfc2898.txt

PBKDF1应用哈希函数,该函数应为MD2[6]、MD5[19]或SHA-1[18]来派生密钥。派生密钥的长度受限于哈希函数输出的长度,对于MD2和MD5,长度为16个八位字节,对于SHA-1,长度为20个八位字节。PBKDF1与PKCS#5 v1.5中的密钥派生过程兼容。由于其产生的密钥可能对某些应用程序来说不够大,因此只建议使用PBKDF1来兼容现有应用程序。

PBKDF2应用伪随机函数(见附录B.1的示例)来派生密钥。派生密钥的长度基本上是无限的。(但是,派生密钥的最大有效搜索空间可能会受到底层伪随机函数结构的限制。请参见附录B.1进行进一步讨论。)推荐在新的应用程序中使用PBKDF2。

请执行以下操作:

openssl enc -aes-256-cbc -pbkdf2 -iter 20000 -in hello -out hello.enc -k meow

openssl enc -d -aes-256-cbc -pbkdf2 -iter 20000 -in hello.enc -out hello.out

注意:在解密时迭代次数必须与加密时的迭代次数相同。

迭代次数必须至少为10000。以下是关于迭代次数的一个好答案:https://security.stackexchange.com/a/3993

还有……我们已经有足够多的人推荐 GPG 了,请认真阅读问题。


注意:PBKDF2现在已成为openssl enc的一部分(终于)。 然而,迭代次数非常低,需要设置为更高的水平。如果该计数是随机的,则还可以为加密提供额外的“盐度”级别。 - anthony
这篇文章很棒。它还提示我们,与其选择高计数(线性增加计算资源),我们可以使用具有高熵的强密码,使计算复杂度呈指数增长。每增加 10 位熵相当于将迭代计数乘以 1000。例如,如果您拥有 >28 个随机字符(从 62 个字符集中选择)作为密码,您就无需担心迭代计数。 - oᴉɹǝɥɔ
如果在这两个语句之下,您定义了使用的所有开关和命令,那将非常有益。 - Andrew S
-k是什么?在man页面中找不到。 - Andrew S
@AndrewS - 第一行:使用aes-256-cbc作为"密码命令",-pbkdf2是"基于密码的密钥派生函数,第二代",-iter是密钥派生函数运行的迭代次数,-in是输入文件,-out是加密/解密的结果,-k是密码本身。第二个命令将提示输入密码,在这种情况下是meow。为了安全起见,请使用比meow要长得多的密码。请注意,我通常使用-pass file:keyfilekeyfile通常是一个64个或更多字符的文件。您将需要它来解密,所以不要丢失它! - undefined

15

如其他答案所述,之前版本的openssl使用了一个弱密钥派生函数来从密码中派生AES加密密钥。然而,openssl v1.1.1支持更强的密钥派生函数,其中密钥是使用pbkdf2和随机生成的盐以及多次sha256哈希(默认为10,000次)从密码中派生出来的。

要加密一个文件:

openssl aes-256-cbc -e -salt -pbkdf2 -iter 10000 -in plaintextfilename -out encryptedfilename

解密文件的步骤:

openssl aes-256-cbc -d -salt -pbkdf2 -iter 10000 -in encryptedfilename -out plaintextfilename

注意:使用Web Crypto API在JavaScript中有一个等效/兼容的实现,可以在https://github.com/meixler/web-browser-based-file-encryption-decryption找到。


由于这些选项不断变化,这意味着您需要记录创建每个 OpenSSL 加密文件时使用的选项。特别是迭代计数应随时间增加!对于一个解决方案,请参见相对简单的 openssl enc 包装器...“keepout”https://antofthy.gitlab.io/software/#keepout 它可以扩展以包括更多的 OpenSSL 随着时间的推移。 - anthony
你需要解释所有这些开关,否则它只是一段神奇的代码,没有提供任何理解。 - Andrew S
1
@AndrewS同意 - openssl的man页面并不像其他大多数页面那样友好。你需要明确知道,你需要查看man enc,以获取有关使用openssl enc的选项。 - undefined

8

加密:

$ openssl bf < arquivo.txt > arquivo.txt.bf

解密:

$ openssl bf -d < arquivo.txt.bf > arquivo.txt

bf === 在CBC模式下的Blowfish算法


这个在 OpenSSL 3 中不起作用,是被写入的。 - velcrow

8

使用随机生成的公钥进行更新。

加密:

openssl enc -aes-256-cbc -a -salt -in {raw data} -out {encrypted data} -pass file:{random key}

解密:

openssl enc -d -aes-256-cbc -in {ciphered data} -out {raw data}

最好该页面仍然在线且使用https。 - Ewoks

3

我在网上找到了一个开源程序,它使用openssl来加密和解密文件。它只需要一个密码就可以完成这个任务。这个开源脚本的好处是它通过碎片化文件删除原始未加密文件。但是它的危险之处在于,一旦原始未加密文件被删除,你必须确保记住你的密码,否则将没有其他方法来解密你的文件。

这是它在github上的链接

https://github.com/EgbieAnderson1/linux_file_encryptor/blob/master/file_encrypt.py


使用openssl进行文件加密时,情况已经发生了变化,现在有更多的选项需要记住,以便成功解密加密文件。其中一个解决方案是“keepout” https://antofthy.gitlab.io/software/#keepout - anthony

2
请注意,OpenSSL CLI使用一种弱的非标准算法将口令转换为密钥,并安装GPG会导致各种文件添加到您的主目录并运行gpg-agent后台进程。如果您想要最大的便携性和控制现有工具,则可以使用PHP或Python访问较低级别的API,并直接传递完整的AES密钥和IV。
通过Bash示例PHP调用:
IV='c2FtcGxlLWFlcy1pdjEyMw=='
KEY='Twsn8eh2w2HbVCF5zKArlY+Mv5ZwVyaGlk5QkeoSlmc='
INPUT=123456789023456

ENCRYPTED=$(php -r "print(openssl_encrypt('$INPUT','aes-256-ctr',base64_decode('$KEY'),OPENSSL_ZERO_PADDING,base64_decode('$IV')));")
echo '$ENCRYPTED='$ENCRYPTED
DECRYPTED=$(php -r "print(openssl_decrypt('$ENCRYPTED','aes-256-ctr',base64_decode('$KEY'),OPENSSL_ZERO_PADDING,base64_decode('$IV')));")
echo '$DECRYPTED='$DECRYPTED

这将输出:
$ENCRYPTED=nzRi252dayEsGXZOTPXW
$DECRYPTED=123456789023456

你还可以使用PHP的openssl_pbkdf2函数来安全地将口令转换为密钥。

Openssl CLI现在已经实现并警告用户应该使用PBKDF2进行密码哈希。然而,它的默认迭代次数非常低,需要更大的值。 - anthony

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