[英]What is the time complexity of crypt function in Linux?
Unix中用於身份驗證的加密功能如下所述:
char *crypt(const char *key, const char *salt);
假設我有key
(長度為n )和salt
(長度為m ),調用此函數的時間復雜度(算法順序)是多少?
從crypt
的手冊頁:
salt是從
[a-zA-Z0-9./]
集中選擇的兩個字符的字符串。 該字符串用於以4096種不同方式之一干擾算法。
和
通過獲取密鑰的前八個字符中每個字符的最低7位,可以獲得56位密鑰。
然后,將由此獲得的密鑰用於加密恆定字符串(使用經過調整的DES算法),這需要花費固定時間。 因此,該函數對於任何有效參數都具有恆定的運行時。 請注意,這種截斷會導致密碼很弱。
正如melpomene所評論的那樣 ,某些實現對crypt
函數提供了擴展,從而允許選擇更安全的模式。 對於以下內容,我假設您正在使用GNU C庫中的crypt
函數。 該手冊說:
對於基於MD5的算法, salt應該由字符串
$1$
,后跟最多8個字符,並以另一個$
或字符串結尾結尾。crypt
的結果為salt,如果不以salt結尾,則加一個$
,然后是字母./0-9A-Za-z
的22個字符,最多34個字符。 密鑰中的每個字符都很重要。
由於鹽的長度由恆定和密碼散列函數具有固定在輸入的長度的時間復雜度是線性的,整體的時間復雜度crypt
功能將在鍵是線性的。
除MD5之外,我的glibc版本還支持更安全的SHA-256 (通過$5$
選擇)和SHA-512 (通過$6$
選擇)加密哈希函數。 它們的輸入長度也具有線性時間復雜度。
由於我無法完成目前實際上應該執行的任務,因此我為各種crypt
方法計時,以支持上述分析。 這是結果。
繪制了針對key
串長度在crypt
函數中花費的執行時間。 每個數據系列都覆蓋有線性回歸,但DES除外,在DES中繪制了平均值。 我感到驚訝的是SHA-512實際上比SHA-256 快 。
用於基准測試的代碼在此處( benchmark.c
)。
#define _GNU_SOURCE /* crypt */
#include <errno.h> /* errno, strerror */
#include <stdio.h> /* FILE, fopen, fclose, fprintf */
#include <stdlib.h> /* EXIT_{SUCCESS,FAILURE}, malloc, free, [s]rand */
#include <string.h> /* size_t, strlen */
#include <assert.h> /* assert */
#include <time.h> /* CLOCKS_PER_SEC, clock_t, clock */
#include <unistd.h> /* crypt */
/* Barrier to stop the compiler from re-ordering instructions. */
#define COMPILER_BARRIER asm volatile("" ::: "memory")
/* First character in the printable ASCII range. */
static const char ascii_first = ' ';
/* Last character in the printable ASCII range. */
static const char ascii_last = '~';
/*
Benchmark the time it takes to crypt(3) a key of length *keylen* with salt
*salt*. The result is written to the stream *ostr* so its computation cannot
be optimized away.
*/
static clock_t
measure_crypt(const size_t keylen, const char *const salt, FILE *const ostr)
{
char * key;
const char * passwd;
clock_t t1;
clock_t t2;
size_t i;
key = malloc(keylen + 1);
if (key == NULL)
return ((clock_t) -1);
/*
Generate a random key. The randomness is extremely poor; never do this in
cryptographic applications!
*/
for (i = 0; i < keylen; ++i)
key[i] = ascii_first + rand() % (ascii_last - ascii_first);
key[keylen] = '\0';
assert(strlen(key) == keylen);
COMPILER_BARRIER;
t1 = clock();
COMPILER_BARRIER;
passwd = crypt(key, salt);
COMPILER_BARRIER;
t2 = clock();
COMPILER_BARRIER;
fprintf(ostr, "%s\n", passwd);
free(key);
return t2 - t1;
}
/*
The program can be called with zero or one arguments. The argument, if
given, will be used as salt.
*/
int
main(const int argc, const char *const *const argv)
{
const size_t keymax = 2000;
const size_t keystep = 100;
const char * salt = ".."; /* default salt */
FILE * devnull = NULL; /* redirect noise to black hole */
int status = EXIT_SUCCESS;
size_t keylen;
if (argc > 1)
salt = argv[1];
devnull = fopen("/dev/null", "r");
if (devnull == NULL)
goto label_catch;
srand((unsigned) clock());
for (keylen = 0; keylen <= keymax; keylen += keystep)
{
clock_t ticks;
double millis;
ticks= measure_crypt(keylen, salt, devnull);
if (ticks < 0)
goto label_catch;
millis = 1.0E3 * ticks / CLOCKS_PER_SEC;
fprintf(stdout, "%16zu %e\n", keylen, millis);
}
goto label_finally;
label_catch:
status = EXIT_FAILURE;
fprintf(stderr, "error: %s\n", strerror(errno));
label_finally:
if (devnull != NULL)
fclose(devnull);
return status;
}
用於回歸和繪圖的Gnuplot腳本在此處( plot.gplt
)。
set terminal 'svg'
set output 'timings.svg'
set xrange [0 : *]
set yrange [0 : *]
set key top left
set title 'crypt(3) benchmarks'
set xlabel 'key length / bytes'
set ylabel 'computation time / milliseconds'
des(x) = a_des
md5(x) = a_md5 + b_md5 * x
sha256(x) = a_sha256 + b_sha256 * x
sha512(x) = a_sha512 + b_sha512 * x
fit des(x) 'timings.des' via a_des
fit md5(x) 'timings.md5' via a_md5, b_md5
fit sha256(x) 'timings.sha256' via a_sha256, b_sha256
fit sha512(x) 'timings.sha512' via a_sha512, b_sha512
plot des(x) w l notitle lc '#75507b' lt 1 lw 2.5, \
'timings.des' w p t 'DES' lc '#5c3566' pt 7 ps 0.8, \
md5(x) w l notitle lc '#cc0000' lt 1 lw 2.5, \
'timings.md5' w p t 'MD5' lc '#a40000' pt 7 ps 0.8, \
sha256(x) w l notitle lc '#73d216' lt 1 lw 2.5, \
'timings.sha256' w p t 'SHA-256' lc '#4e9a06' pt 7 ps 0.8, \
sha512(x) w l notitle lc '#3465a4' lt 1 lw 2.5, \
'timings.sha512' w p t 'SHA-512' lc '#204a87' pt 7 ps 0.8
最后,Makefile用於將所有內容掛鈎( GNUmakefile
)。
CC := gcc
CPPFLAGS :=
CFLAGS := -Wall -O2
LDFLAGS :=
LIBS := -lcrypt
all: benchmark timings.svg timings.png
benchmark: benchmark.o
${CC} -o $@ ${CFLAGS} $^ ${LDFLAGS} ${LIBS}
benchmark.o: benchmark.c
${CC} -c ${CPPFLAGS} ${CFLAGS} $<
timings.svg: plot.gplt timings.des timings.md5 timings.sha256 timings.sha512
gnuplot $<
timings.png: timings.svg
convert $< $@
timings.des: benchmark
./$< '$(shell pwgen -ncs 2)' > $@
timings.md5: benchmark
./$< '$$1$$$(shell pwgen -ncs 8)' > $@
timings.sha256: benchmark
./$< '$$5$$$(shell pwgen -ncs 16)' > $@
timings.sha512: benchmark
./$< '$$6$$$(shell pwgen -ncs 16)' > $@
clean:
rm -f benchmark benchmark.o fit.log $(wildcard *.o timings.*)
.PHONY: all clean
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.