openssl 学习之enc中salt参数解析

当我们使用openssl  enc 命令工具进行加密的时候,涉及到一个参数 即salt,下面简单分析一下salt参数。salt说白了就是一个随机数,salt与passwd串联,然后计算其hash值来防御dictionary attacks 和预计算的rainbow table 攻击。在openssl 的enc 命令中,通过salt 与passwd 来生加密(解密)密钥和初始向量IV。

一,openssl中enc 中salt相关参数

需要注意的就是,当仅设置-K时,还需要设置IV。

-pass arg
the password source. For more information about the format of arg see the PASS PHRASE ARGUMENTS section in openssl(1).

-salt
use a salt in the key derivation routines. This is the default.

-nosalt
don't use a salt in the key derivation routines. This option SHOULD NOT be used except for test purposes or compatibility with ancient versions of OpenSSL and SSLeay.

-k password
the password to derive the key from. This is for compatibility with previous versions of OpenSSL. Superseded by the -pass argument.

-kfile filename
read the password to derive the key from the first line of filename. This is for compatibility with previous versions of OpenSSL. Superseded by the -pass argument.

-nosalt
do not use a salt

-salt
use salt (randomly generated or provide with -S option) when encrypting (this is the default).

-S salt
the actual salt to use: this must be represented as a string of hex digits.

-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 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.

二,openssl中enc.c 文件分析

enc.c文件是openssl中enc命令对应的源码,我们专注于salt相关参数,故只摘录部分代码。

首先我们来看一下,openssl中调用 EVP_BytesToKey通过passwd和salt来生成Key 和IV,在enc.c 中有如下代码

//line 555 Opensl1.0.1c
EVP_BytesToKey(cipher,dgst,sptr,(unsigned char *)str,
				strlen(str),1,key,iv);
//函数原型
//line 115 Evp_key.c Openssl1.0.1c
int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md, 
	     const unsigned char *salt, const unsigned char *data, int datal,
	     int count, unsigned char *key, unsigned char *iv)

通过函数原型,除了str 参数,其他参数我们非常容易看清其意思。我们向前查找,发现各个参数的意思以及具体如何定义的。

1,dgst 为MD5

//line 340~343 Openssl1.0.1c 
//摘要算法使用MD5
if (dgst == NULL)
{
dgst = EVP_md5();

2,sptr 为salt 

//line513~ 553 
if (str != NULL)
{
	/* Salt handling: if encrypting generate a salt and
	 * write to output BIO. If decrypting read salt from
	 * input BIO.
	 */
	unsigned char *sptr;
	if(nosalt) sptr = NULL;//如果参数制定nosalt 则sptr为NULL
	else {
		if(enc) {
			/**line 270~274 用户指定salt值
 			**else if (strcmp(*argv,"-S") == 0)
			**{
			**	if (--argc < 1) goto bad;
			**	hsalt= *(++argv);
			**}
			**/
			if(hsalt) {
			if(!set_hex(hsalt,salt,sizeof salt)) {
				BIO_printf(bio_err,"invalid hex salt value\n");
				goto end;
				}
			} else if (RAND_pseudo_bytes(salt, sizeof salt) < 0)
				goto end;
			/* If -P option then don't bother writing */
			if((printkey != 2)&& (BIO_write(wbio,magic,
				sizeof magic-1) != sizeof magic-1
			        || BIO_write(wbio,(char *)salt,sizeof salt) != sizeof salt)) {
				BIO_printf(bio_err,"error writing output file\n");
				goto end;
				}
			} else if(BIO_read(rbio,mbuf,sizeof mbuf) != sizeof mbuf
				|| BIO_read(rbio,(unsigned char *)salt,sizeof salt) != sizeof salt){
				BIO_printf(bio_err,"error reading input file\n");
					goto end;
			} else if(memcmp(mbuf,magic,sizeof magic-1)) {
				    BIO_printf(bio_err,"bad magic number\n");
				    goto end;
		}

	sptr = salt;
}

3,str为passwd

//line 180~184 Openssl1.0.1c
else if (strcmp(*argv,"-pass") == 0) // passwd 参数,新版本,替代-k
{
	if (--argc < 1) goto bad;
	passarg= *(++argv);
}//line 223~227 Openssl1.0.1celse 
if (strcmp(*argv,"-k") == 0)// passwd 参数,旧版本,建议使用-pass参数
{
        if (--argc < 1) 
        goto bad;
        str= *(++argv);
}
//line 414~421 Openssl1.0.1c
if(!str && passarg) {
	if(!app_passwd(bio_err, passarg, NULL, &pass, NULL)) {
	BIO_printf(bio_err, "Error getting password\n");
	goto end;
	}
	str = pass;
}

三,EVP_BytesToKey 函数

EVP_BytesToKey函数的功能就是生产key和iv。

int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md, 
	     const unsigned char *salt, const unsigned char *data, int datal,
	     int count, unsigned char *key, unsigned char *iv)
	{
	EVP_MD_CTX c;
	unsigned char md_buf[EVP_MAX_MD_SIZE];
	int niv,nkey,addmd=0;
	unsigned int mds=0,i;
	int rv = 0;
	nkey=type->key_len;
	niv=type->iv_len;
	OPENSSL_assert(nkey <= EVP_MAX_KEY_LENGTH);
	OPENSSL_assert(niv <= EVP_MAX_IV_LENGTH);

	if (data == NULL) return(nkey);

	EVP_MD_CTX_init(&c);
	for (;;)
		{
		if (!EVP_DigestInit_ex(&c,md, NULL))
			return 0;
		if (addmd++)
			if (!EVP_DigestUpdate(&c,&(md_buf[0]),mds))
				goto err;
                // 将passwd和salt串联进行hash
		if (!EVP_DigestUpdate(&c,data,datal))
			goto err;
		if (salt != NULL)
			if (!EVP_DigestUpdate(&c,salt,PKCS5_SALT_LEN))
				goto err;
		if (!EVP_DigestFinal_ex(&c,&(md_buf[0]),&mds))
			goto err;

		for (i=1; i<(unsigned int)count; i++)// 对hash结果再进行count次hash
			{
			if (!EVP_DigestInit_ex(&c,md, NULL))
				goto err;
			if (!EVP_DigestUpdate(&c,&(md_buf[0]),mds))
				goto err;
			if (!EVP_DigestFinal_ex(&c,&(md_buf[0]),&mds))
				goto err;
			}
		i=0;
		if (nkey)//设置key
			{
			for (;;)
				{
				if (nkey == 0) break;
				if (i == mds) break;
				if (key != NULL)
					*(key++)=md_buf[i];
				nkey--;
				i++;
				}
			}
		if (niv && (i != mds))//设置IV
			{
			for (;;)
				{
				if (niv == 0) break;
				if (i == mds) break;
				if (iv != NULL)
					*(iv++)=md_buf[i];
				niv--;
				i++;
				}
			}
		if ((nkey == 0) && (niv == 0)) break;
		}
	rv = type->key_len;
	err:
	EVP_MD_CTX_cleanup(&c);
	OPENSSL_cleanse(&(md_buf[0]),EVP_MAX_MD_SIZE);
	return rv;
	}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值