PlarSSL源码,是最小巧的ssl代码库。高效、便于移植和集成。尤其适合嵌入式应用。PlarSSL没有相应的pem格式,只有基础的加解密方法。
RSA相关API
1. 基本数据结构
typedef struct
{
int ver; /*!< always 0 */
size_t len; /*!< size(N) in chars */
mpi N; /*!< public modulus */
mpi E; /*!< public exponent */
mpi D; /*!< private exponent */
mpi P; /*!< 1st prime factor */
mpi Q; /*!< 2nd prime factor */
mpi DP; /*!< D % (P - 1) */
mpi DQ; /*!< D % (Q - 1) */
mpi QP; /*!< 1 / (Q % P) */
mpi RN; /*!< cached R^2 mod N */
mpi RP; /*!< cached R^2 mod P */
mpi RQ; /*!< cached R^2 mod Q */
int padding; /*!< RSA_PKCS_V15 for 1.5 padding and
RSA_PKCS_v21 for OAEP/PSS */
int hash_id; /*!< Hash identifier of md_type_t as
specified in the md.h header file
for the EME-OAEP and EMSA-PSS
encoding */
}
rsa_context;
2. mpi单元
//初始化一个mpi结构
void mpi_init( mpi *X );
//释放一个mpi
void mpi_free( mpi *X );
//扩大指定mpi数量
int mpi_grow( mpi *X, size_t nblimbs );
//复制一个mpi结构单元
int mpi_copy( mpi *X, const mpi *Y );
//交换两个mpi单元位置
void mpi_swap( mpi *X, mpi *Y );
//设置int值到mpi单元
int mpi_lset( mpi *X, t_sint z );
//读取mpi单元
int mpi_get_bit( const mpi *X, size_t pos );
//读取第0位的mpi的比特数
size_t mpi_lsb( const mpi *X );
//返回mpi的比特数
size_t mpi_msb( const mpi *X );
//返回mpi总长度
size_t mpi_size( const mpi *X );
//读入字符串到mpi中
int mpi_read_string( mpi *X, int radix, const char *s );
//导出mpi的字符串
int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen );
3. RSA密钥管理
//初始化rsa上下文,设置padding,当padding==RSA_PKCS_V15,hash_id被忽略
void rsa_init( rsa_context *ctx, int padding, int hash_id);
//生成rsa密钥对
int rsa_gen_key( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
unsigned int nbits, int exponent );
//校验公钥信息
int rsa_check_pubkey( const rsa_context *ctx );
//校验私钥信息
int rsa_check_privkey( const rsa_context *ctx );
3. RSA加解密
/* 使用PKCS#1加密文本
* \param ctx RSA上下文
* \param f_rng 生成随机数函数
* \param p_rng 生成随机数函数参数
* \param mode 加密模式RSA_PUBLIC 或 RSA_PRIVATE
* \param ilen 明文长度
* \param input 要加密的明文
* \param output 将要获得的密文
*
* \return 0表示成功
*/
int rsa_pkcs1_encrypt( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode, size_t ilen,
const unsigned char *input,
unsigned char *output );
/* 解密文本
* \param ctx RSA上下文
* \param mode RSA_PUBLIC或 RSA_PRIVATE
* \param olen 将要获得的明文长度
* \param input 密文数据
* \param output 将要获得的明文
* \param output_max_len 明文存储空间的最大长度
*
* \return 0表示成功
*/
int rsa_pkcs1_decrypt( rsa_context *ctx,
int mode, size_t *olen,
const unsigned char *input,
unsigned char *output,
size_t output_max_len );
4. RSA签名和验签
/** 封装PKCS#1签名,使用rsa的私钥对信息摘要进行签名
* \param ctx RSA上下文
* \param f_rng 生成随机数函数
* \param p_rng 生成随机数函数参数
* \param mode RSA_PUBLIC或RSA_PRIVATE
* \param hash_id 摘要算法SIG_RSA_RAW, SIG_RSA_MD{2,4,5}或SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen 信息摘要长度
* \param hash 信息摘要内容
* \param sig 将要获取到的签名信息
*
* \return 0表示成功
*/
int rsa_pkcs1_sign( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
int hash_id,
unsigned int hashlen,
const unsigned char *hash,
unsigned char *sig );
/** 封装PKCS#1验签,使用公钥校验信息摘要
* \param ctx rsa公钥
* \param mode RSA_PUBLIC 或 RSA_PRIVATE
* \param hash_id 摘要算法SIG_RSA_RAW, SIG_RSA_MD{2,4,5} 或SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen 摘要信息长度
* \param hash 摘要信息
* \param sig 要验证的签名信息
*
* \return 0表示成功
*/
int rsa_pkcs1_verify( rsa_context *ctx,
int mode,
int hash_id,
unsigned int hashlen,
const unsigned char *hash,
unsigned char *sig );
RSA编程示例
#define KEY_LEN 128
#define RSA_N "9292758453063D803DD603D5E777D788" \
"8ED1D5BF35786190FA2F23EBC0848AEA" \
"DDA92CA6C3D80B32C4D109BE0F36D6AE" \
"7130B9CED7ACDF54CFC7555AC14EEBAB" \
"93A89813FBF3C4F8066D2D800F7C38A8" \
"1AE31942917403FF4946B0A83D3D3E05" \
"EE57C6F5F5606FB5D4BC6CD34EE0801A" \
"5E94BB77B07507233A0BC7BAC8F90F79"
#define RSA_E "10001"
#define RSA_D "24BF6185468786FDD303083D25E64EFC" \
"66CA472BC44D253102F8B4A9D3BFA750" \
"91386C0077937FE33FA3252D28855837" \
"AE1B484A8A9A45F7EE8C0C634F99E8CD" \
"DF79C5CE07EE72C7F123142198164234" \
"CABB724CF78B8173B9F880FC86322407" \
"AF1FEDFDDE2BEB674CA15F3E81A1521E" \
"071513A1E85B5DFA031F21ECAE91A34D"
#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
"2C01CAD19EA484A87EA4377637E75500" \
"FCB2005C5C7DD6EC4AC023CDA285D796" \
"C3D9E75E1EFC42488BB4F1D13AC30A57"
#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \
"E211C2B9E5DB1ED0BF61D0D9899620F4" \
"910E4168387E3C30AA1E00C339A79508" \
"8452DD96A9A5EA5D9DCA68DA636032AF"
#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \
"3C94D22288ACD763FD8E5600ED4A702D" \
"F84198A5F06C2E72236AE490C93F07F8" \
"3CC559CD27BC2D1CA488811730BB5725"
#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \
"D8AAEA56749EA28623272E4F7D0592AF" \
"7C1F1313CAC9471B5C523BFE592F517B" \
"407A1BD76C164B93DA2D32A383E58357"
#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \
"F38D18D2B2F0E2DD275AA977E2BF4411" \
"F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
"A74206CEC169D74BF5A8C50D6F48EA08"
#define PT_LEN 10
#define RSA_PT "helo rsa"
static int myrand(void *rng_state, unsigned char *output, size_t len) {
size_t i;
if (rng_state != NULL)
rng_state = NULL;
for (i = 0; i < len; ++i)
output[i] = rand();
return (0);
}
/*
* Checkup routine
*/
int rsa_self_test(int verbose) {
size_t len;
rsa_context rsa;
unsigned char rsa_plaintext[PT_LEN];
unsigned char rsa_decrypted[PT_LEN];
unsigned char rsa_ciphertext[KEY_LEN];
#if defined(POLARSSL_SHA1_C)
unsigned char sha1sum[20];
#endif
rsa_init(&rsa, RSA_PKCS_V15, 0);
rsa.len = KEY_LEN;
mpi_read_string(&rsa.N, 16, RSA_N);
mpi_read_string(&rsa.E, 16, RSA_E);
mpi_read_string(&rsa.D, 16, RSA_D);
mpi_read_string(&rsa.P, 16, RSA_P);
mpi_read_string(&rsa.Q, 16, RSA_Q);
mpi_read_string(&rsa.DP, 16, RSA_DP);
mpi_read_string(&rsa.DQ, 16, RSA_DQ);
mpi_read_string(&rsa.QP, 16, RSA_QP);
printf("RSA Test\n");
if (verbose != 0)
printf(" RSA key validation: ");
if (rsa_check_pubkey(&rsa) != 0 || rsa_check_privkey(&rsa) != 0) {
if (verbose != 0)
printf("failed\n");
return (1);
}
memcpy(rsa_plaintext, RSA_PT, PT_LEN);
printf("\n加密前的字符:%s \n", rsa_plaintext);
if (verbose != 0)
printf("passed\n PKCS#1 encryption : ");
if (rsa_pkcs1_encrypt(&rsa, &myrand, NULL, RSA_PUBLIC, PT_LEN, rsa_plaintext, rsa_ciphertext) != 0) {
if (verbose != 0)
printf("failed\n");
return (1);
}
if (verbose != 0)
printf("passed\n PKCS#1 decryption : ");
if (rsa_pkcs1_decrypt(&rsa, RSA_PRIVATE, &len, rsa_ciphertext, rsa_decrypted, sizeof(rsa_decrypted)) != 0) {
if (verbose != 0)
printf("failed\n");
return (1);
}
if (memcmp(rsa_decrypted, rsa_plaintext, len) != 0) {
if (verbose != 0)
printf("failed\n");
return (1);
}
printf("\n解密后的字符:%s \n", rsa_decrypted);
#if defined(POLARSSL_SHA1_C)
if (verbose != 0)
printf("passed\n PKCS#1 data sign : ");
sha1(rsa_plaintext, PT_LEN, sha1sum);
if (rsa_pkcs1_sign(&rsa, NULL, NULL, RSA_PRIVATE, SIG_RSA_SHA1, 20, sha1sum, rsa_ciphertext) != 0) {
if (verbose != 0)
printf("failed\n");
return (1);
}
if (verbose != 0)
printf("passed\n PKCS#1 sig. verify: ");
if (rsa_pkcs1_verify(&rsa, RSA_PUBLIC, SIG_RSA_SHA1, 20, sha1sum, rsa_ciphertext) != 0) {
if (verbose != 0)
printf("failed\n");
return (1);
}
if (verbose != 0)
printf("passed\n\n");
#endif /* POLARSSL_SHA1_C */
rsa_free(&rsa);
return (0);
}
输出的结果为:
RSA Test
RSA key validation:
加密前的字符:helo rsa
passed
PKCS#1 encryption : passed
PKCS#1 decryption :
解密后的字符:helo rsa
passed
PKCS#1 data sign : passed
PKCS#1 sig. verify: passed
对于拿到私钥pem如何调试验证程序
1.验证公钥加密,私钥解密
使用程序对字符串:helo rsa
字段进行加密,加密后转化为base64编码。结果为:
加密前:
helo rsa
编码后:
NogGOEbfZ7YZn1G+8GO82MPXxWVYO964187G1ZhdYq1bS3Lvit2IRP66UFY9/ffSW2Ck1HN0BQ/mhwkTQRWnmdvby15amOnV6/XABEYAz0156ai1klpocCoFNqHwwO498gp3tSUUW0ULPgpPtXdWK8jkNAgALhasg7wHKXOk1p/xgSWtDPj+7LqZ45ooKCcA+xMbMXeYH1hs0zsFzp842rVWAThj5TBIhG0xfY80hKPrsAXDiOe19OUJf0+uZbSrI/so3yiI2mnosgfq12Srw5JFl9X3wDI+lKA3xOO1dcDYNbfpacPzaRRz/vxr0ZJJ67Uc5i+48/BFqTUPc+dcUw==
将编码文件存储至rsa_encrypt_encode.txt
文件。
(1)base64解码操作
base64 -d rsa_encrypt_encode.txt > rsa_encrypt.txt
(2)私钥解密
openssl rsautl -decrypt -in rsa_encrypt.txt -inkey rsa_pri.key -out rsa_decrypt.txt
结果为:helo rsa
2.验证公钥验签
通过首先获取文件摘要,长度为40个字符。
$ openssl dgst -sha1 file.txt
SHA1(file.txt)= 52b60977ce28dd6c0c6f096f722d9d9fbaba0dd5
然后对文件摘要进行签名:
$ openssl dgst -sha1 -sign rsa_pri_2048.key -out sign_file.txt file.txt
然后对签名后的文件进行base64编码:
$ base64 sign_file.txt > sign_file_base64.txt
然后使用代码公钥进行验签。
3.私钥加密,公钥解密
首先对文件进行加密:
$ openssl rsautl -encrypt -in rsa_decrypt.txt -inkey rsa_pri_2048.pem -out rsa_encrypt.txt
然后对加密后的文件进行base64编码:
$ base64 rsa_encrypt.txt > rsa_encrypt_base64.txt
然后使用代码公钥进行解密。