⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rsa.cpp

📁 RSA加密解密的算法例程
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
 *  The RSA PK cryptosystem
 *
 *  Copyright (C) 2006  Christophe Devine
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License, version 2.1 as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *  MA  02110-1301  USA
 */
/*
 *  RSA was designed by Ron Rivest, Adi Shamir and Len Adleman.
 *
 *  http://theory.lcs.mit.edu/~rivest/rsapaper.pdf
 *  http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf
 */

#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE 1
#endif

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "rsa.h"

/*
 * Generate a RSA keypair of nbits in size according
 * to the specified public exponent.
 *
 * Function "rng_func" takes one argument (rng_state)
 * and should return a random unsigned long.
 *
 * Returns 0 if successful, or ERR_RSA_KEYGEN_FAILED.
 */
int rsa_gen_key( rsa_context *ctx, uint nbits, uint exponent,
                 ulong (*rng_func)(void *), void *rng_state )
{
    int ret;
    mpi P1, Q1, H, G;

    mpi_init( &P1, &Q1, &H, &G, NULL );

    memset( ctx, 0, sizeof( rsa_context ) );

    /*
     * find primes P and Q with Q < P so that
     * GCD( E, (P-1)*(Q-1) ) == 1
     */
    CHK( mpi_lset( &ctx->E, exponent ) );

    do
    {
        CHK( mpi_gen_prime( &ctx->P, nbits / 2, 0,
                            rng_func, rng_state ) );

        CHK( mpi_gen_prime( &ctx->Q, nbits / 2, 0,
                            rng_func, rng_state ) );

        if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 )
            mpi_swap( &ctx->P, &ctx->Q );

        CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) );
        CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
        CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
        CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
        CHK( mpi_gcd( &G, &ctx->E, &H  ) );
    }
    while( mpi_cmp_int( &G, 1 ) != 0 );

    /*
     * D  = E^-1 mod ((P-1)*(Q-1))
     * DP = D mod (P - 1)
     * DQ = D mod (Q - 1)
     * QP = Q^-1 mod P
     */
    CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H  ) );
    CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
    CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
    CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );

    ctx->len = ( mpi_size( &ctx->N ) + 7 ) >> 3;

cleanup:

	debug_print(&P1);
	debug_print(&Q1);
	debug_print(&H);
	debug_print(&G);
    mpi_free( &P1, &Q1, &H, &G, NULL );

    if( ret != 0 )
    {
        rsa_free( ctx );
        return( ERR_RSA_KEYGEN_FAILED | ret );
    }

    return( 0 );   
}

/*
 * Perform an RSA public key operation. This function
 * does not take care of message padding: both ilen and
 * olen must be equal to the modulus size (ctx->len).
 *
 * Returns 0 if successful, or ERR_RSA_PUBLIC_FAILED.
 */
int rsa_public( rsa_context *ctx, uchar *input,  uint ilen,
                                  uchar *output, uint olen )
{
    int ret;
    mpi T;

    if( ilen != ctx->len || olen != ctx->len )
        return( ERR_RSA_PUBLIC_FAILED );

    mpi_init( &T, NULL );

    CHK( mpi_import( &T, input, ilen ) );

    if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
    {
		debug_print(&T);
        mpi_free( &T, NULL );
        return( ERR_RSA_PUBLIC_FAILED );
    }

    CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N ) );
    CHK( mpi_export( &T, output, &olen ) );

cleanup:
	debug_print(&T);		//32
    mpi_free( &T, NULL );

    if( ret != 0 )
        return( ERR_RSA_PUBLIC_FAILED | ret );

    return( 0 );
}

/*
 * Perform an RSA private key operation. This function
 * does not take care of message padding: both ilen an
 * olen must be equal to the modulus size (ctx->len).
 *
 * Returns 0 if successful, or ERR_RSA_PRIVATE_FAILED.
 */
int rsa_private( rsa_context *ctx, uchar *input,  uint ilen,
                                   uchar *output, uint olen )
{
    int ret;
    mpi T, T1, T2;

    if( ilen != ctx->len || olen != ctx->len )
        return( ERR_RSA_PRIVATE_FAILED );

    mpi_init( &T, &T1, &T2, NULL );

    CHK( mpi_import( &T, input, ilen ) );

    if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 )
    {
		debug_print(&T);
        mpi_free( &T, NULL );
        return( ERR_RSA_PRIVATE_FAILED );
    }

#if 0
    CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N ) );
#else
    /*
     * faster decryption using the CRT
     *
     * T1 = input ^ dP mod P
     * T2 = input ^ dQ mod Q
     */
    CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P ) );
    CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q ) );

    /*
     * T = (T1 - T2) * (Q^-1 mod P) mod P
     */
    CHK( mpi_sub_mpi( &T, &T1, &T2 ) );
    CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) );
    CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) );

    /*
     * output = T2 + T * Q
     */
    CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) );
    CHK( mpi_add_mpi( &T, &T2, &T1 ) );

#endif

    CHK( mpi_export( &T, output, &olen ) );

cleanup:
	debug_print(&T);	//32
	debug_print(&T1);	//32
	debug_print(&T2);	//16
	mpi_free( &T, &T1, &T2, NULL );

    if( ret != 0 )
        return( ERR_RSA_PRIVATE_FAILED | ret );

    return( 0 );
}

/*
 * Returns 0 if the public key is valid,
 * or ERR_RSA_KEY_CHECK_FAILED.
 */
int rsa_check_pubkey( rsa_context *ctx )
{
    if( ( ctx->N.p[0] & 1 ) == 0 || 
        ( ctx->E.p[0] & 1 ) == 0 )
        return( ERR_RSA_KEY_CHECK_FAILED );

    if( mpi_size( &ctx->N ) < 128 ||
        mpi_size( &ctx->N ) > 4096 )
        return( ERR_RSA_KEY_CHECK_FAILED );

    if( mpi_size( &ctx->E ) < 2 ||
        mpi_size( &ctx->E ) > 64 )
        return( ERR_RSA_KEY_CHECK_FAILED );

    return( 0 );
}

/*
 * Returns 0 if the private key is valid,
 * or ERR_RSA_KEY_CHECK_FAILED.
 */
int rsa_check_privkey( rsa_context *ctx )
{
    int ret = 0;
    mpi TN, P1, Q1, H, G;

    mpi_init( &TN, &P1, &Q1, &H, &G, NULL );

    CHK( mpi_mul_mpi( &TN, &ctx->P, &ctx->Q ) );
    CHK( mpi_sub_int( &P1, &ctx->P, 1 ) );
    CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) );
    CHK( mpi_mul_mpi( &H, &P1, &Q1 ) );
    CHK( mpi_gcd( &G, &ctx->E, &H  ) );

    if( mpi_cmp_mpi( &TN, &ctx->N ) == 0 &&
        mpi_cmp_int( &G, 1 ) == 0 )
    {
		debug_print(&TN);	//32
		debug_print(&P1);	//16
		debug_print(&Q1);	//16
		debug_print(&H);	//32
		debug_print(&G);	//2
        mpi_free( &TN, &P1, &Q1, &H, &G, NULL );
        return( 0 );
    }

cleanup:
	debug_print(&TN);
	debug_print(&P1);
	debug_print(&Q1);
	debug_print(&H);
	debug_print(&G);
    mpi_free( &TN, &P1, &Q1, &H, &G, NULL );
    return( ERR_RSA_KEY_CHECK_FAILED | ret );
}

/*
 * Add the PKCS1 v1.5 padding and perform a public RSA.
 *
 *      ctx     points to an RSA public key
 *      input   buffer holding the data to be encrypted
 *      ilen    length of the plaintext; cannot be longer
 *              than the modulus, minus 3+8 for padding
 *      output  buffer that will hold the ciphertext
 *      olen    must be the same as the modulus size
 *              (for example, 128 if RSA-1024 is used)
 *
 * Returns 0 if successful, or ERR_RSA_ENCRYPT_FAILED
 */
int rsa_pkcs1_encrypt( rsa_context *ctx,
                       uchar *input,  uint ilen,
                       uchar *output, uint olen )
{
    int nb_pad;
    uchar *p = output;

    if( olen != ctx->len || olen < ilen + 11 )
        return( ERR_RSA_ENCRYPT_FAILED );

    nb_pad = olen - 3 - ilen;

    *p++ = 0;
    *p++ = RSA_CRYPT;

    while( nb_pad-- > 0 )
    {
        do { *p = (uchar) rand(); } while( *p == 0 );
        p++;
    }

    *p++ = 0;
    memcpy( p, input, ilen );

    if( rsa_public( ctx, output, olen, output, olen ) != 0 )
        return( ERR_RSA_ENCRYPT_FAILED );

    return( 0 );
}

/*
 * Perform a private RSA and remove the PKCS1 v1.5 padding.
 *
 *      ctx     points to an RSA private key
 *      input   buffer holding the encrypted data
 *      ilen    must be the same as the modulus size
 *      output  buffer that will hold the plaintext
 *      olen    size of output buffer, will be updated
 *              to contain the length of the plaintext
 *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -