什么是加密
加密是一种将数据转换为不可用的形式的方法,只能通过解密才能使数据有用。目的是使数据仅适用于可以解密的数据(即使其可用)。通常,需要对数据进行加密,以确保在未经授权访问的情况下无法获得数据。这是攻击者设法通过授权系统并访问控制的最后一条防线。
这并不意味着所有数据都需要加密,因为通常会授权和访问系统可能足够,此外,加密和解密数据也会受到性能罚款。如果数据被加密以及何时是应用程序计划和风险评估的问题,有时也是监管要求,例如HIPAA或GDPR。
。数据可以在磁盘上进行加密,例如在磁盘上或运输中,例如通过互联网通信的两个方之间的数据。
在这里,您将学习如何使用密码(也称为对称加密)加密和解密数据。此密码必须向双方交换信息。
密码,摘要,盐,iv
要正确且安全地使用加密,需要解释一些概念。
密码是用于加密的算法。例如,AES256是密码。密码的想法是大多数人在加密方面会想到的。
摘要基本上是一种哈希函数,用于在密码使用密码之前拼命和延长密码(即加密密钥)。为什么要这样做?首先,它创建了一个钥匙良好的均匀长度,可以更好地加密。它也非常适合“盐”,这是下一个要谈论的。
“盐”是击败所谓的“彩虹”桌子的一种方法。攻击者知道,如果原件是两个哈希值仍然看起来完全相同。但是,如果您将盐值添加到哈希中,那么它们就不会。它被称为“盐”,因为它与钥匙混合在一起,以产生不同的东西。现在,彩虹表将尝试将已知的哈希值与预先计算的数据匹配,以猜测密码。通常,为每个键随机生成盐并与其储存。为了匹配已知的哈希斯,攻击者将不得不将彩虹表的预定为许多随机值,这通常是不可行的。
您经常会在加密中听到有关“迭代”的消息。迭代是一个单个循环,其中将钥匙和盐混合在一起,以使猜测钥匙更加困难。这是多次这样做的,因此攻击者在计算上很难逆转钥匙,因此“迭代”(复数)。通常,所需的最小迭代数为1000,但可能与之不同。如果您从非常强的密码开始,通常需要更少。
iv(或“初始化向量”)通常是一个随机值,用于加密每个消息。现在,盐用于根据密码生产钥匙。当您已经有了密钥并且现在正在加密消息时,使用IV。 IV的目的是在加密时使相同的消息出现不同。有时,IV也具有顺序组件,因此它由随机字符串和不断增加的顺序制成。这使得“重播”攻击变得困难,这是攻击者不需要解密消息的地方;但是,“嗅探”(即发件人和接收器之间的拦截),然后重播,希望重复已经执行的操作。尽管实际上,大多数高级协议已经有一个序列,在该序列中,每条消息作为其中的一部分,是一个增加的数据包号,因此在大多数情况下,IV不需要它。
先决条件
此示例使用Vely框架的C编程语言。
请注意,使用自定义密码和摘要,以及自初始化向量和密钥缓存的明确使用自15.2起 - 如果您使用的是较早的版本,则应使用install 15.2或较早地运行这些示例。
> >加密示例
要在此处运行示例,请在其自己的目录中创建一个应用程序(请参阅vf有关Vely的计划经理的更多信息):
mkdir enc_example
cd enc_example
sudo vf -i -u $(whoami) enc
加密数据使用encrypt-data语句。最简单的形式是加密零端的字符串。创建一个文件âemprypt.vely'并复制以下内容:
#include "vely.h"
void encrypt() {
out-header default
char *str = "This contains a secret code, which is Open Sesame!";
// Encrypt
encrypt-data str to define enc_str password "my_password"
p-out enc_str
@
// Decrypt
decrypt-data enc_str password "my_password" to define dec_str
p-out dec_str
@
}
您可以看到加密数据和decrypt-data的基本用法。您可以提供数据(原始或加密),密码,然后使用。数据被加密然后解密,产生原始内容。
在“源代码”中,字符串变量–enc_strâ(以char *的形式创建)将包含加密版本 - 这包含一个打开的秘密代码芝麻!dec_strâ将是解密的数据,必须完全相同。
要从命令行运行此代码,请首先制作应用程序:
vv -q
然后,请生成bash代码来运行它的请求路径是/加密,在我们的情况下,它是通过函数来处理的。在源文件中定义。在Vely中,这些名称始终匹配,使其易于编写,读取和执行代码。在vv中使用-râ选项来指定请求路径并获取您需要运行程序的代码:
vv -r --req="/encrypt"
这将产生类似的东西:
export REQUEST_METHOD=GET
export SCRIPT_NAME="/enc"
export PATH_INFO="/encrypt"
export QUERY_STRING=""
/var/lib/vv/bld/enc/enc
复制并将其粘贴到bash壳中并执行。您将得到答复:
Content-type: text/html;charset=utf-8
Cache-Control: max-age=0, no-cache
Pragma: no-cache
Status: 200 OK
72ddd44c10e9693be6ac77caabc64e05f809290a109df7cfc57400948cb888cd23c7e98e15bcf21b25ab1337ddc6d02094232111aa20a2d548c08f230b6d56e9
This contains a secret code, which is Open Sesame!
您在这里拥有的是加密的数据,然后使用相同的密码解密此加密数据。毫不奇怪,结果与我们首先加密的字符串匹配。
请注意,默认情况下,加密数据将以可读的十六进制形式产生加密价值,这意味着由十六进制字符组成,而不是9到9和a' fâ。这样,您可以将加密的数据存储到常规字符串中。例如,它可能转到JSON文档或数据库中的VARCHAR列,或其他任何地方。但是,您还可以生成二进制加密数据。稍等一下。
以上结果是具有适当标头的有效HTTP响应。要跳过标题,请将变量设置为vv_silent_header to是:
export VV_SILENT_HEADER=yes
/var/lib/vv/bld/enc/enc
如果您执行程序 - /var/lib/vv/bld/enc/enc/exc/enc/exc/exc/exc/exc/exc/exc/exc/exc/exc/exc/exc/exc/exc/exc/exc/ext in hish oft the hith Ith Ith Ith Ith Ins nobone:
72ddd44c10e9693be6ac77caabc64e05f809290a109df7cfc57400948cb888cd23c7e98e15bcf21b25ab1337ddc6d02094232111aa20a2d548c08f230b6d56e9
This contains a secret code, which is Open Sesame!
将数据加密到二进制结果中
在上一个示例中,所得的加密数据是人类可读的十六进制形式。您还可以创建二进制加密数据,该数据不是人类可读的字符串,也较短。为此,请使用二进制子句。用:
替换代码。
#include "vely.h"
void encrypt() {
out-header default
char *str = "This contains a secret code, which is Open Sesame!";
// Encrypt
encrypt-data str to define enc_str password "my_password" \
binary output-length define outlen
// Save the encrypted data to a file
write-file "encrypted_data" from enc_str length outlen
get-app directory to define app_dir
@Encrypted data written to file <<p-out app_dir>>/encrypted_data
// Decrypt data
decrypt-data enc_str password "my_password" \
input-length outlen binary to define dec_str
p-out dec_str
@
}
当您想获得二进制加密数据时,您也应该在字节中获得其长度,否则您可能不知道它的结尾,因为它可能包含其中的空字符。为此,请使用输出长度子句。在此代码中,将变量的加密数据写入file``egenpted_data'',而书面的长度为“删除”字节。当文件写入没有路径的情况下,它始终写在应用程序主目录中(请参阅how_vely_works),因此您使用get-app来获取该目录。
解密数据时,请注意使用输入长度子句。它说已加密数据具有多少个字节。显然,您可以从Outlen varible中获得它,其中加密数据存储了加密数据的长度。当加密和解密被解耦时,即在单独的程序中运行时,您可以确保可提供此长度。
还请注意,当数据加密为二进制(意味着产生二进制输出)时,解密必须使用相同。
制作应用程序:
vv -q
与以前相同的运行:
export REQUEST_METHOD=GET
export SCRIPT_NAME="/enc"
export PATH_INFO="/encrypt"
export QUERY_STRING=""
/var/lib/vv/bld/enc/enc
结果是:
Encrypted data written to file /var/lib/vv/enc/app/encrypted_data
This contains a secret code, which is Open Sesame!
解密的数据与原始数据完全相同。
您可以通过使用八倍垃圾箱(ODâ)Linux实用程序看到将实际的加密数据写入文件:
$ od -c /var/lib/vv/enc/app/encrypted_data
0000000 r 335 324 L 020 351 i ; 346 254 w 312 253 306 N 005
0000020 370 \t ) \n 020 235 367 317 305 t \0 224 214 270 210 315
0000040 # 307 351 216 025 274 362 033 % 253 023 7 335 306 320
0000060 224 # ! 021 252 242 325 H 300 217 # \v m V 351
0000100
你有。您会注意到数据是二进制的,实际上包含空字符。
加密二进制数据
在这些示例中加密的数据是一个字符串,即null-deledimited。您可以通过在输入长度子句中指定其长度,例如将其复制到gencrypt.vely。
#include "vely.h"
void encrypt() {
out-header default
char *str = "This c\000ontains a secret code, which is Open Sesame!";
// Encrypt
encrypt-data str to define enc_str password "my_password" \
input-length 12
p-out enc_str
@
// Decrypt
decrypt-data enc_str password "my_password" to define dec_str \
output-length define res_len
// Output binary data; present null char as octal \000
int i;
for (i = 0; i < res_len; i++) {
if (dec_str[i] == 0) {
p-out "\\000"
} else {
pf-out "%c", dec_str[i]
}
}
@
}
这将在内存位置加密12个字节,而不管有任何空字符。在这种情况下,该c的含义是null字符,然后是“ Ontain”字符串,但可以是任何类型的二进制数据,例如JPG文件的内容。
在解密侧,您可以获得在输出长度子句中解密的字节数。最后,被解密的数据被证明是原始的,而空字符以典型的八进表示形式表示。
制作应用程序:
vv -q
与以前相同的运行:
export REQUEST_METHOD=GET
export SCRIPT_NAME="/enc"
export PATH_INFO="/encrypt"
export QUERY_STRING=""
/var/lib/vv/bld/enc/enc
结果是:
6bea45c2f901c0913c87fccb9b347d0a
This c\000ontai
加密的值较短,因为在这种情况下数据也较短,结果与原始相匹配。
使用任何密码或摘要
默认使用的加密是来自标准OpenSSL库中的AES256和SHA256哈希,这两个库都广泛用于密码学中。但是,您可以使用OpenSSL支持的任何可用密码和摘要(即哈希)(即使是您提供的自定义)。
要查看可用的算法,请在命令行中执行此操作:
#get list of cipher providers
openssl list -cipher-algorithms
#get list of digest providers
openssl list -digest-algorithms
这两个将提供密码和摘要(哈希)算法的列表。其中一些可能比Vely选择的默认值弱,而另一些则可能只是为了与旧系统的向后兼容。然而,其他人可能是很新的,并且没有足够的时间在您希望的范围内得到验证。因此,选择这些算法时要小心,并确保知道为什么要更改默认的算法。也就是说,这里是使用Camellia-256(即Camellia-256-CFB1)加密的一个例子。用:
替换代码。
#include "vely.h"
void encrypt() {
out-header default
char *str = "This contains a secret code, which is Open Sesame!";
// Encrypt data
encrypt-data str to define enc_str password "my_password" \
cipher "CAMELLIA-256-CFB1" digest "SHA3-512"
p-out enc_str
@
// Decrypt data
decrypt-data enc_str password "my_password" to define dec_str \
cipher "CAMELLIA-256-CFB1" digest "SHA3-512"
p-out dec_str
@
}
制作应用程序:
vv -q
运行它:
export REQUEST_METHOD=GET
export SCRIPT_NAME="/enc"
export PATH_INFO="/encrypt"
export QUERY_STRING=""
/var/lib/vv/bld/enc/enc
在这种情况下,结果是:
f4d64d920756f7220516567727cef2c47443973de03449915d50a1d2e5e8558e7e06914532a0b0bf13842f67f0a268c98da6
This contains a secret code, which is Open Sesame!
再次获得原始数据。请注意,您必须在加密数据和解密数据中使用相同的密码和摘要!
当然,您可以像以前一样使用二进制和输出长度子句产生二进制加密值。
如果您获得了加密数据的外部系统,并且您知道它们使用了哪种密码和消化,则可以匹配这些密码并使代码可互操作。 Vely使用标准OpenSL库,以便其他软件也可能。
使用盐
要加入加密,请使用盐分。您可以使用random-string语句生成随机盐。这是“ eNcrypt.vely”的代码:
#include "vely.h"
void encrypt() {
out-header default
char *str = "This contains a secret code, which is Open Sesame!";
// Get salt
random-string to define rs length 16
// Encrypt data
encrypt-data str to define enc_str password "my_password" salt rs
@Salt used is <<p-out rs>>, and the encrypted string is <<p-out enc_str>>
// Decrypt data
decrypt-data enc_str password "my_password" salt rs to define dec_str
p-out dec_str
@
}
制作应用程序:
vv -q
运行几次:
export REQUEST_METHOD=GET
export SCRIPT_NAME="/enc"
export PATH_INFO="/encrypt"
export QUERY_STRING=""
/var/lib/vv/bld/enc/enc
/var/lib/vv/bld/enc/enc
/var/lib/vv/bld/enc/enc
结果:
Salt used is VA9agPKxL9hf3bMd, and the encrypted string is 3272aa49c9b10cb2edf5d8a5e23803a5aa153c1b124296d318e3b3ad22bc911d1c0889d195d800c2bd92153ef7688e8d1cd368dbca3c5250d456f05c81ce0fdd
This contains a secret code, which is Open Sesame!
Salt used is FeWcGkBO5hQ1uo1A, and the encrypted string is 48b97314c1bc88952c798dfde7a416180dda6b00361217ea25278791c43b34f9c2e31cab6d9f4f28eea59baa70aadb4e8f1ed0709db81dff19f24cb7677c7371
This contains a secret code, which is Open Sesame!
Salt used is nCQClR0NMjdetTEf, and the encrypted string is f19cdd9c1ddec487157ac727b2c8d0cdeb728a4ecaf838ca8585e279447bcdce83f7f95fa53b054775be1bb2de3b95f2e66a8b26b216ea18aa8b47f3d177e917
This contains a secret code, which is Open Sesame!
您可以看到,每个加密都会生成一个随机盐值(在这种情况下为16个字节),并且每次加密值都不同,即使被加密的数据是相同的!这使得很难像这样破解加密。
请注意,如果盐为二进制值,通常会更好。在这种情况下,它是一个字符串,例如。
当然,要解密,您必须记录盐并完全像加密时一样使用盐。在此处的代码中,可变rs持有盐。如果将加密值存储在数据库中,则可能会将盐存储在旁边。
初始化向量
实际上,您不会为每个消息使用不同的盐值。它每次都会创建一个新钥匙,并且可以降低性能。而且确实没有必要:盐的使用是使每个键(甚至是相同的键)更难猜测。完成此操作后,您可能不需要再做一次或经常。
相反,您将对每个消息使用IV(初始化向量)。通常,这是一个随机字符串,使相同的消息看起来不同,并增加了破解密码的计算成本。这是“ Encrypt.vely”的新代码:
#include "vely.h"
void encrypt() {
out-header default
// Get salt
random-string to define rs length 16
// Encrypt data
num i;
for (i = 0; i < 10; i++) {
random-string to define iv length 12
encrypt-data "The same message" to define enc_str password "my_password" salt rs iterations 2000 init-vector iv cache
@The encrypted string is <<p-out enc_str>>
// Decrypt data
decrypt-data enc_str password "my_password" salt rs iterations 2000 init-vector iv to define dec_str cache
p-out dec_str
@
}
}
制作应用程序:
vv -q
运行几次:
export REQUEST_METHOD=GET
export SCRIPT_NAME="/enc"
export PATH_INFO="/encrypt"
export QUERY_STRING=""
/var/lib/vv/bld/enc/enc
/var/lib/vv/bld/enc/enc
/var/lib/vv/bld/enc/enc
结果可能是:
The encrypted string is 787909d332fd84ba939c594e24c421b00ba46d9c9a776c47d3d0a9ca6fccb1a2
The same message
The encrypted string is 7fae887e3ae469b666cff79a68270ea3d11b771dc58a299971d5b49a1f7db1be
The same message
The encrypted string is 59f95c3e4457d89f611c4f8bd53dd5fa9f8c3bbe748ed7d5aeb939ad633199d7
The same message
The encrypted string is 00f218d0bbe7b618a0c2970da0b09e043a47798004502b76bc4a3f6afc626056
The same message
The encrypted string is 6819349496b9f573743f5ef65e27ac26f0d64574d39227cc4e85e517f108a5dd
The same message
The encrypted string is a2833338cf636602881377a024c974906caa16d1f7c47c78d9efdff128918d58
The same message
The encrypted string is 04c914cd9338fcba9acb550a79188bebbbb134c34441dfd540473dd8a1e6be40
The same message
The encrypted string is 05f0d51561d59edf05befd9fad243e0737e4a98af357a9764cba84bcc55cf4d5
The same message
The encrypted string is ae594c4d6e72c05c186383e63c89d93880c8a8a085bf9367bdfd772e3c163458
The same message
The encrypted string is 2b28cdf5a67a5a036139fd410112735aa96bc341a170dafb56818dc78efe2e00
The same message
您可以看到加密时出现相同的消息不同,尽管当解密时又是相同的。当然,密码,盐,迭代次数和初始矢量必须相同,以均与加密和解密相同。
请注意,在加密数据和decrypt-data中使用“缓存”子句。它有效地缓存了计算的密钥(给定密码,盐,密码/消化算法和迭代次数),因此并非每次通过循环计算。使用“缓存”键一次计算一次,然后将另一个iv(在“ init-vector”子句中)用于每个消息。
如果您想偶尔重建钥匙,请使用提供布尔值的“ clear-cache”子句。如果是真的,则重新计算钥匙,否则它是单独的。请参阅encrypt-data 2。
结论
您已经学习了如何使用不同的密码,摘要,盐和IV值加密和解密数据。您还可以创建一个人类可读的加密价值和二进制输出,以及加密字符串和二进制值(如文档)。
图像版权(c)Sergio Mijatovic 2023
本文根据CC-BY-4.0许可,该文章允许在商业上复制和重新分发 - 有关更多详细信息,请参见许可。