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


205

我想使用一个密码来加密和解密一个文件。

如何使用OpenSSL做到这一点?


2
您应该使用来从密码中导出Key和IV PKCS5_PBKDF2_HMAC。您应该使用EVP_*函数进行加密和解密。请参阅OpenSSL Wiki上的EVP对称加密和解密。实际上,您可能应该使用经过身份验证的加密,因为它既提供机密性又提供真实性。请参阅OpenSSL Wiki上的EVP身份验证加密和解密
jww

3
从您的问题中不明白为什么要使用OpenSSL。以下评论显示GPG更好-也是出于安全原因。stackoverflow.com/a/31552829/952234我投反对票。
Yaroslav Nikitenko '16

Answers:


261

安全警告:AES-256-CBC不提供经过身份验证的加密,并且容易遭受填充oracle攻击。您应该改用age等

加密:

openssl aes-256-cbc -a -salt -in secrets.txt -out secrets.txt.enc

解密:

openssl aes-256-cbc -d -a -in secrets.txt.enc -out secrets.txt.new

有关各种标志的更多详细信息


18
根据OP的用例,答案可能不是最佳的(在撰写本文时)。具体来说,参数“ -a”可能不是最佳的,答案也无法解释其用法。当以ASCII /文本形式传输加密输出时,通常使用“ -a”,与二进制形式相比,具有增加输出大小的效果。原始海报没有指定输出格式,因此我认为至少应该提到这一点。请参阅答案:stackoverflow.com/a/31552829/952234,该文档还包含有关为什么要为此任务使用gpg而不是openssl的注释。
moo

7
由于没有密钥派生,因此请勿使用上述命令。在此处了解更多信息:openssl弱密钥派生
jonasl

还应指定一个密钥,或提及其来源。它加强了吗?
可调式

2
@jonasl根据最新的手册页指出:“在Openssl 1.1.0中,默认摘要已从MD5更改为SHA256。” 来源:github.com/openssl/openssl/blob/master/doc/man1/enc.pod
Kebman

2
-md sha256如果您打算在另一台计算机上使用此文件,则可以在@Kebman的注释中添加您的编码和解码命令。这样
可以避免

162

简短答案:

您可能想使用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 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.

补充笔记:

尽管您曾特别询问过OpenSSL,但出于本文的目的,您可能要考虑使用GPG进行加密,而本文基于OpenSSL和GPG来加密异地备份?

要使用GPG进行相同的操作,请使用以下命令:

加密:

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

解密:

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

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


8
关于首选GPG而非OpenSSL的好评论。我发现令人难以置信的是,OpenSSL使用如此弱的密码派生哈希作为密钥!
2016年

2
请确保使用“ -md md5”选项与在未指定-md选项的情况下在较旧的openssl上加密的文件兼容,否则您将发现文件在较新的系统上不会解密:github.com/libressl-portable/便携式/问题/ 378
山姆·利迪科特

1
默认值在opensl版本之间更改。1.0.x对-md选项使用默认值md5。版本1.1.x使用sha256。如果您解密并收到“:数字信封例程:EVP_DecryptFinal_ex:错误解密”错误。尝试指定“ -md md5”或“ -md sha256”。
txyoji

1
“加密或解密时将提示您输入密码。” gpg让我解密文件而没有提示您输入密码。好像密码已存储了一段时间,我不想这样。
user76284 '19

1
@moo 即使--no-symkey-cache将gpg与一起使用,该选项似乎也禁用了缓存--symmetric
user76284 '19

32

加密:

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)文档。


11
要使用纯文本密码,请替换-k symmetrickey-pass stdin-pass 'pass:PASSWORD'
Zenexer

3
由于没有密钥派生,因此请勿使用上述命令。在此处了解更多信息:openssl弱密钥派生
jonasl

4
与@jonasl的评论相关,请注意这-k symmetrickey具有误导性。该-k选项用于指定密码,OpenSSL从该密码派生对称密钥。如果要指定对称密钥,则必须使用该-K选项。
user1071847

13

请勿使用OPENSSL默认密钥派生。

目前,已接受的答案已在使用它,因此不再推荐和安全使用。

对于攻击者而言,简单地蛮力破解密钥是非常可行的。

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

PBKDF1应用散列函数(应为MD2 [6],MD5 [19]或SHA-1 [18])来导出密钥。派生密钥的长度受哈希函数输出的长度限制,对于MD2和MD5,哈希长度为1​​6个八位位组,对于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。阅读该死的问题。


4

加密:

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

解密:

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

bf === CBC模式下的河豚



3

请注意,OpenSSL CLI使用弱非标准算法将密码短语转换为密钥,并且将GPG安装结果添加到添加到主目录中的各种文件中,并运行gpg-agent后台进程。如果要最大程度地实现可移植性并使用现有工具进行控制,则可以使用PHP或Python访问较低级别的API,并直接传递完整的AES Key和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进行密码哈希处理。但是,其默认迭代计数非常低,并且需要更大。
安东尼

2

我在网上找到一个开源程序,它使用openssl加密和解密文件。只需一个密码即可完成此操作。这个开源脚本的妙处在于,它通过切碎文件来删除原始未加密的文件。但是危险的是,一旦原始未加密的文件消失了,您必须确保记住密码,否则它们就无法解密文件。

这里的链接在github上

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


使用openssl进行文件加密时,情况发生了变化,它们还有很多其他选择,需要记住这些选择,以便您可以成功解密加密的文件。一种解决方法是“禁入” antofthy.gitlab.io/software/#keepout
安东尼

2

如其他答案中所述,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

随着这些选项不断变化,这意味着您还需要记录创建每个openssl加密文件时使用了哪些选项。尤其是随着迭代次数随时间增加!对于一种解决方案 ,可以将openssl封装为一个相对简单的包装器。“ 保留antofthy.gitlab.io/software/#keepout随着时间的推移,它可以扩展为包含更多的openssl。
安东尼

@anthony看起来像是一个有用的项目。另请参见github.com/meixler/web-browser-based-file-encryption-decryption
mti2935,

0

对mti2935的附加注释很好的答案。

似乎迭代次数越多越能防止暴力破解,并且您应该使用较高的迭代次数,因为这样才能在性能/资源上提供合理的价格。

在我的旧版Intel i3-7100上,加密了一个相当大的文件1.5GB:

 time openssl enc -aes256 -e -pbkdf2 -iter 10000 -pass pass:"mypassword" -in "InputFile" -out "OutputFile"
 Seconds: 2,564s

 time openssl enc -aes256 -e -pbkdf2 -iter 262144 -pass pass:"mypassword" -in "InputFile" -out "OutputFile"
 Seconds:  2,775s

没什么区别,虽然没有检查内存使用情况(?)

在当今的GPU以及明天更快的情况下,我想每秒钟可能进行数十亿次蛮力迭代。

12年前,a NVIDIA GeForce 8800 Ultra可以迭代超过200.000百万/秒的迭代(不过是MD5哈希)

来源:Ainane-Barrett-Johnson-Vivar-OpenSSL.pdf

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.