PolarSSL的RSA算法密钥格式

最近在新作一个东西,需要用到RSA算法,不想用OpenSSL的算法库了,决定使用稍微轻量级一些的PolarSSL的算法库。现在的需求是需要使用PolarSSL的RSA算法产生RSA密钥对,需要提取出公钥数据和私钥数据,并且可以把公钥和私钥提供给其他支持RSA的产品使用,比如USBKEY,加密狗、或者其他的RSA算法库。也需要把第三方产生的RSA密钥对可以拿来进行公钥运算或者私钥运算。按理说,只要可以提取出公钥模数N,和私钥因子D(或者DP,DQ)就可以了,PolarSSL的算法库应该没什么问题,产生的RSA对象里面这些因子都是现成的,研究一下数据对象的读写就应该能搞定了,但是同事说公钥填充N和E=0x10001没问题,私钥只写D或者P和Q就是没搞定,好久没有看这个了,决定拿来研究一下。


RSA的加密算法不多说了,网上可以找到各种专业的介绍。先看PolarSSL的RSA算法库中rsa_context的定义吧。

/**
 * \brief          RSA context structure
 */
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;

可以看到rsa_context中有公钥模数N和公钥指数E,私钥D和P,Q,DP,DQ,QP等,如果只用N、D、E或者P和Q的话,是应该可以进行私钥运算的,但是PolarSSL的算法有个rsa_check_pubkey/rsa_check_prikey函数来检查公私钥格式是否正确,公钥给N和E赋值可以检查通过,私钥单独给N、D、E或者P、Q赋值,检查私钥格式是失败的,查看一下rsa_check_prikey的内容看下格式错误在什么地方。

/*
 * Check a private RSA key
 */
int rsa_check_privkey( const rsa_context *ctx )
{
    int ret;
    mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2;

    if( ( ret = rsa_check_pubkey( ctx ) ) != 0 )
        return( ret );

    if( !ctx->P.p || !ctx->Q.p || !ctx->D.p )
        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED );

    mpi_init( &PQ ); mpi_init( &DE ); mpi_init( &P1 ); mpi_init( &Q1 );
    mpi_init( &H  ); mpi_init( &I  ); mpi_init( &G  ); mpi_init( &G2 );
    mpi_init( &L1 ); mpi_init( &L2 );

    MPI_CHK( mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) );
    MPI_CHK( mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) );
    MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
    MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
    MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
    MPI_CHK( mpi_gcd( &G, &ctx->E, &H  ) );

    MPI_CHK( mpi_gcd( &G2, &P1, &Q1 ) );
    MPI_CHK( mpi_div_mpi( &L1, &L2, &H, &G2 ) );  
    MPI_CHK( mpi_mod_mpi( &I, &DE, &L1  ) );

    /*
     * Check for a valid PKCS1v2 private key
     */
    if( mpi_cmp_mpi( &PQ, &ctx->N ) != 0 ||
        mpi_cmp_int( &L2, 0 ) != 0 ||
        mpi_cmp_int( &I, 1 ) != 0 ||
        mpi_cmp_int( &G, 1 ) != 0 )
    {
        ret = POLARSSL_ERR_RSA_KEY_CHECK_FAILED;
    }

    
cleanup:

    mpi_free( &PQ ); mpi_free( &DE ); mpi_free( &P1 ); mpi_free( &Q1 );
    mpi_free( &H  ); mpi_free( &I  ); mpi_free( &G  ); mpi_free( &G2 );
    mpi_free( &L1 ); mpi_free( &L2 );

    if( ret == POLARSSL_ERR_RSA_KEY_CHECK_FAILED )
        return( ret );

    if( ret != 0 )
        return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED + ret );

    return( 0 );
}
检查函数是要查看N、E是否有效,还要用D、P、Q进行验证,所以需要自己使用私钥P和Q计算出剩余的元素,然后填充的rsa_context中去。

首先定义了自己的中国余数定理的RSA私钥结构和RSA公钥结构,如下:

/*
	/brief  RSA CRT format privatekey
	P,Q
	bit = 1024/2048
*/
typedef struct
{
	int				bit;				
	unsigned char	P[128];
	unsigned char	Q[128];
}rsa_crt_prikey;

/*
	/brief		RSA public key
	bit = 1024/2048
	N
	E=0x10001;//default
*/
typedef	struct
{
	int			bit;
	unsigned	N[256];
}rsa_pubkey;

公钥指数E固定使用0x10001,就不在结构里单独写了。然后封装了一个函数从rsa_context中提取出公钥和私钥数据,两个函数是使用公钥或者私钥数据填充rsa_context结构。

/*
	把CRT格式的RSA私钥填充到rsa_context中去
*/
int rsa_fill_crt_privatekey(rsa_context *ctx, rsa_crt_prikey *prikey)
{
	int	ret;
	mpi P1,Q1,H;
	mpi_init(&P1);	mpi_init(&Q1);	mpi_init(&H);
	//
	rsa_init(ctx,RSA_PKCS_V15,RSA_PKCS_V21);
	//
	mpi_read_binary(&ctx->P, prikey->P, prikey->bit/16);//从CRT格式的私钥中读取P

	mpi_read_binary(&ctx->Q, prikey->Q, prikey->bit/16);//从CRT格式的私钥中读取Q
	mpi_read_binary(&ctx->E, (unsigned char*)"\x00\x01\x00\x01", 4);//填充固定的指数E=0x10001
	//
	MPI_CHK(mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ));//计算N,N=P*Q
	//
	MPI_CHK(mpi_sub_int( &P1, &ctx->P, 1 ));
	MPI_CHK(mpi_sub_int( &Q1, &ctx->Q, 1 ));
	MPI_CHK(mpi_mul_mpi( &H, &P1, &Q1 ));
	MPI_CHK(mpi_inv_mod( &ctx->D , &ctx->E, &H  ));//计算出D,D=(P-1)*(Q-1) MOD E
	MPI_CHK(mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ));//计算DP
	MPI_CHK(mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ));//计算DP

	MPI_CHK(mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ));//计算QP
	//
	ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3;//填充长度
	//
	ret = rsa_check_privkey(ctx);
cleanup:
	mpi_free(&P1);	mpi_free(&Q1);	mpi_free(&H);
	return ret;	
}
/*
	把公钥模N填充到rsa_context中去
*/
int rsa_fill_publickey(rsa_context *ctx,  rsa_pubkey *pubkey)
{
	int ret;
	//
	rsa_init(ctx,RSA_PKCS_V15,RSA_PKCS_V21);
	//
	mpi_read_binary(&ctx->N, pubkey->N, pubkey->bit/8);
	mpi_read_binary(&ctx->E, (unsigned char*)"\x00\x01\x00\x01", 4);
	//
	ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3;
	//
	ret = rsa_check_pubkey(ctx);
	//
	return ret;
}
/*
*	\brief			get crt private key and public key from rsa_context
*/
int	rsa_getkeypairs(rsa_context* ctx, rsa_crt_prikey *prikey, rsa_pubkey *pubkey)
{
	int	ret;
	//
	if (NULL != prikey)
	{
		prikey->bit = ctx->len * 8;
		ret = mpi_write_binary(&ctx->P, prikey->P, ctx->len/2);
		if (0 != ret)
		{ 
			return ret;
		}
		ret = mpi_write_binary(&ctx->Q, prikey->Q, ctx->len/2);
		if (0 != ret)
		{ 
			return ret;
		}
	}
	//
	if (NULL != pubkey)
	{
		pubkey->bit = ctx->len * 8;
		ret = mpi_write_binary(&ctx->N,pubkey->N, ctx->len);
		if (0 != ret)
		{ 
			return ret;
		}
	}
	//
	return 0;
}
//
这样使用这个rsa算法产生密钥对后可以使用上面的rsa_getkeypairs提取出公钥和私钥数据给其他产品或者算法运算,也可以把其他产品或者算法产生的公钥或者私钥数据传给PolarSSL的RSA算法进行运算了。



你可能感兴趣的:(密码,Windows编程)