6,加密入门
6.1,使用密码则安全
非对称加密包括RSA,DSA,Diffie-Hellman...
对称加密包括DES, Triple DES,RC2,RC4,IDEA,RC5,Blowfish,CAST...
使用非对称和对称加密术来安全地发送一个消息:
1,Generate a DES key.
2,Encrypt the message M with the DES key to get M*.
3,Get the recipient's RSA public key.
4,Encrypt the DES key with the recipient's RSA public key to get K*.
5,Send {K*, M*}.
6.1.1,介绍术语key
6.2,CST中的算法命名规则
CST可以简单地使用不同的算法来写程序,它们使用相同的代码结构。例如:CST的BSAPI 产生key 使用bsapi_generate_key_ALG函数,
如果ALG是一个对称算法(des,triple_des,rc2,bsa4,bsa5,rc4),函数产生一个secret key(私钥);如果ALG是一个非对称算法(dsa,rsa),
它则产生一个公钥和私钥对.例如:使用bsapi_generate_key_des来产生一个对称DES的key.
Algorithm ALG
DES des
Triple DES triple_des
RC2 rc2
RC4 rc4
DSA dsa
RSA rsa
BSA4 bsa4
BSA5 bsa5
6.3,产生一个key
通过下面的四步来产生一个key:
1,初始化一个随机数发生器;
2,搜集随机数给发生器做种;
3,如果可能,设置key产生参数;
4,传递发生器和参数到一个key产生函数.
在CST中,key参数结构:
union bsapi_kparam_u
{
bsapi_kparam_des des;
bsapi_kparam_rsa rsa;
bsapi_kparam_dsa_com dsa_com;
bsapi_kparam_dsa_key dsa_key;
bsapi_kparam_rc2 rc2;
bsapi_kparam_rc4 rc4;
}bsapi_kparam;
下面的代码使用这些参数来为DES产生一个key:
prng_inst *prng; //pseudo-random number generator
bsapi_kparam kparam; //key generation parameters
if (!(prng = prng_create_bbs(0)))
{
// log error
ut_log0(0UL,UT_ACONTINUE,"Couldn't start prng");
// insert your own error handling code here and stop processing
}
kparam.des.security = DES_NOEIGHTS; // eliminate all weak keys
if (balg->generate_key(prng,&keyblk,0,&kparam))
{
// log error
ut_log0(0UL,UT_ACONTINUE,"Couldn't generate key");
// insert your own error handling code here and stop processing
}
6.4,加密,解密,标记和检验
6.4.1初始化一个session:bsapi_mode,bsapi_kset,prng_create()
在一个加密session能够被启动之前,可靠的初始参数和一个伪随机数产生器必须已经准备好。
信息被传输到session用到两个结构:bsapi_mode和bsapi_kset,bsapi_mode表示算法如何被使用;
bsapi_mode:定义如下:
typedef enum
{
BSAPI_ENCRYPT,BSAPI_DECRYPT,BSAPI_SIGN,BSAPI_VERIFY
}bsapi_mode_op;
typedef enum
{
BSAPI_ECB,BSAPI_CBC,BSAPI_CFB,BSAPI_OFB
}bsapi_mode_mode;
typedef enum
{
BSAPI_SINGLE,BSAPI_TRIPLE,BSAPI_CHAIN3
}bsapi_mode_triple;
typedef enum
{
BSAPI_KEY,BSAPI_SCHEDULE
}bsapi_mode_key_type;
typedef enum
{
BSAPI_ANSI,BSAPI_FAST
}bsapi_mode_fast;
typedef struct bsapi_mode_s
{
bsapi_mode_op op;
bsapi_mode_mode mode;
bsapi_mode_triple triple;
bsapi_mode_key_type key_type;
bsapi_mode_fast fast;
}bsapi_mode;
说明以上结构字段:
op:指明一个session 将用来加密,解密,标记,检验。DES,Triple DES,RC2,RC4,BSA4和BSA5仅能用于加密和解密;
RSA可用于所有的四种;DSA仅能用于标记和检验。
mode:指示哪一个ANSI mode被使用:有下面四种:
(1,BSAPI_ECB--Electronic Code Book;2,BSAPI_CBC--Cipher Block Chaining;3,BSAPI_CFB--Cipher Feedback;4,BSAPI_OFB--Output Feedback)
triple:这个字段仅仅应用于DES和RC2,指示是否triple加密术被使用。
key_type:指示key(s)是作为plain keys(BSAPI_KEY)支持还是作为precomputed subkeys(BSAPI_SCHEDULE)支持。
fast:
bsapi_kset:定义如下:
typedef enum
{
BSAPI_KEY_TYPE_DEFAULT, BSAPI_SECRET, BSAPI_PUBLIC
} bsapi_kset_key_type;
#define BSAPI_PRIVATE BSAPI_SECRET
typedef enum
{
BSAPI_DATA_TYPE_DEFAULT, BSAPI_DATA_TYPE_DATA, BSAPI_DATA_TYPE_HASH
} bsapi_kset_data_type;
typedef struct bsapi_kset_s
{
ut_mblk *keys;
ut_mblk *shrdpub;
#define community shrdpub
u32 effbits; /* effective key-length RC2 only */
ut_mblk *iv;
unsigned feedback; /* OFB and CFB only */
const pad_alg *padalg;
pad_params *padpar;
const hash_alg *hashalg;
unsigned hashbits;
bsapi_kset_data_type data_type; /* when signing/verifying, are we passed
* the message text or its hash */
ut_mblk *pnonce; /* private nonce */
#define k_values pnonce
FILE *pnfprnt; /* footprint database for private nonces */
bsapi_kset_key_type key_type; /* deprecated; use pad_params */
} bsapi_kset;
好的习惯是先这样:
bsapi_kset bkeys = {0};它可以确保一些默认的设置被使用。
6.4.2,一个session例子:加密
所有的CST加密和解密操作使用三个主要的函数:
bsapi_start_ALG():初始化一个session;
bsapi_append_ALG():传递数据给session,开始处理;
bsapi_finish_ALG():结束这个session.
下面的例子说明了上面三个函数:
int descrypt(u8 *in,size_t inlen,u8 **out, size_t *outlen, ut_mblk *key)
{
bsapi_mode md = {BSAPI_ENCRYPT, BSAPI_ECB, BSAPI_SINGLE, BSAPI_KEY, BSAPI_ANSI};
bsapi_kset keys = {0};
bsapi_id mach;
prng_inst *prng;
ut_mblk_list cyph;
ut_mblk_list tmp;
// set parameters
keys.keys = key;
keys.padalg = &pad_pkcs5; // standard padding for DES
prng = prng_create_r48(0); // default parameters
// encrypt
mach = bsapi_start_des(&md, prng, &keys);
bsapi_append_des(in, inlen, mach);
bsapi_finish_des(mach, &cyph);
// get lengthh of output.the output is in cyph, a ut_mblk_list.
// the final item in a list produced by bsapi_finish_ALG() can be identified by
// (item)->next = 0.we add the lengths of the individual output blocks until this confition is true.
*outlen = 0;
for (tmp = cyph;tmp;tmp = tmp->next)
*outlen += tmp->block.used;
// allocate memory for output and copy it over
*out = ut_new_mem(*outlen);
*outlen = 0;
for (tmp = cyph; tmp; tmp = tmp->next)
{
memcpy(*out + *outlen, tmp->block.data, tmp->block.used);
*outlen += tmp->block.used;
}
// free the memory from the list and close down the random number generator
ut_dispose_list(cyph);
prng->destroy(prng);
// return successfully
return 0;
}
6.4.3,一个比较长的session:解密
int longdescrypt (FILE *in, FILE *out, ut_mblk *key)
{
bsapi_mode md = {BSAPI_DECRYPT, BSAPI_ECB, BSAPI_SINGLE, BSAPI_KEY, BSAPI_ANSI};
bsapi_kset keys = {0};
bsapi_id mach;
prng_inst *prng;
ut_mblk_list cyph;
u8 buf[BUFSIZ];
size_t readlen; /* amount read from file */
/* set parameters */
keys.keys = key;
keys.padalg = &pad_pkcs5; /* standard padding for DES */
prng = prng_create_r48 (0); /* default parameters */
/* start encryption session */
mach = bsapi_start_des (&md, prng, &keys);
/* read data from the input file, pass it to the session, and write
* the output from the session to the output file.
* the ut_mblk_list which is produced by bsapi_readmost_des will only*/
while (readlen = fread (buf, sizeof (u8), BUFSIZ, in))
{
bsapi_append_des (buf, readlen, mach);
cyph = bsapi_readmost_des (mach);
for (tmp=cyph; tmp; tmp = tmp->next)
fwrite (tmp->block.data, sizeof (u8), tmp->block.used,out);
ut_dispose_list (cyph);
}
bsapi_finish_des (mach, &cyph);
for (tmp = cyph; tmp; tmp = tmp->next)
fwrite (tmp->block.data, sizeof (u8), tmp->block.used, out);
/* free the memory from the list and close down the random number generator */
ut_dispose_list (cyph);
prng->destroy (prng);
/* return successfully */
return 0;
}
6.4.4,一个session例子:标记和检验
int rsasign (u8 *msg, size_t msglen, ut_mblk *priv, ut_mblk *pub)
{
bsapi_mode md = {0};
bsapi_kset keys = {0};
bsapi_id mach;
ut_mblk_list cyph;
ut_mblk_list tmp;
prng_inst *prng;
int rval = 0; /* default return value is failure */
/* set up signing parameters */
md.op = BSAPI_SIGN;
keys.keys = priv; /* use private key to generate signatures */
keys.padalg = &pad_pkcs1; /* standard for RSA signing */
keys.hashalg = &hash_sha; /* use SHA-1 as hash algorithm */
prng = prng_create_r48 (0);
/* sign */
mach = bsapi_start_rsa (&md, prng, &keys);
bsapi_append_rsa (msg, msglen, mach);
bsapi_finish_rsa (mach, &cyph);
/* cyph contains a single ut_mblk; cyph->block.data is the signature
* data, cyph->block.used is the length of the signature data. For now,
* we simply pass it back to the verification session. */
/* set up verification parameters */
md.op = BSAPI_VERIFY;
keys.keys = pub; /* use public key to verify signatures */
keys.padalg = &pad_ pkcs1; /* standard for RSA signing */
keys.hashalg = &hash_sha; /* use SHA-1 as hash algorithm */
/* verify. Note that the message that was signed is passed to
* bsapi_append_rsa(), while the signature itself is passed to
* bsapi_finish_rsa(). The return value from bsapi_finish_rsa() tells us
* whether the signature was good, the signature was bad, or there was an
* internal failure in the verification session */
mach = bsapi_start_rsa (&md, prng, &keys);
bsapi_append_rsa (msg, msglen, mach);
switch (bsapi_finish_rsa (mach, &cyph))
{
case 0:
printf("validated sig OK./n");
rval = 1;
break;
case 1:
case 2:
printf("Bad Sig!/n");
break;
case -1:
ut_log0 (0UL, UT_ACONTINUE, "internal error in bsapi_finish_rsa()");
/* insert your own error handling code here and stop processing */
break;
default:
printf("Unexpected return value from bsapi_finish_rsa()/n");
}
/* Tidy up and shutdown */
ut_dispose_list (cyph);
prng->destroy (prng);
return rval;
}
6.5,增强特性:bsapi_alg结构