polarssl的RSA使用

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

然后使用代码公钥进行解密。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容