RSA的一些资料

RSA
Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1


目录
1 介绍 3
2 标记法 3
3 密钥类型 4
3.1 RSA公钥 4
3.2 RSA私钥 5
4 数据转换原语 6
4.1 I2OSP 6
4.2 OS2IP 7
5 密码原语 7
5.1 加密解密原语 7
5.1.1 RSAEP 7
5.1.2 RSADP 7
5.2 签名和验证原语 8
6 方案概要 8
7 加密方案 8
7.1 RSAES-OAEP 8
7.2 RSAES-PKCS1-v1_5 8
8 签名方案-附 8
8.1 RSASSA-PSS 8
8.2 RSASSA-PKCS1-v1_5 8
9 签名的编码方式-附 9
9.1 EMSA-PSS 9
9.2 EMSA-PKCS1-v1_5 9
10 Openssl 9
10.1 DER 9
10.2 PEM 9
10.2.1 例子:PEM格式内容 9
10.3 rsa_public_key.pem 10
10.3.1 PEM文件解析 11
附录 A ASN.1语法 19
A.1 RSA 密钥描述 19
A.1.1 RSA 公钥语法 19
A.1.2 RSA 私钥语法 19
A.2 体系验证 20


1 介绍
文档提供了基于RSA算法的公钥密码体系的实现提议,包括以下几个方面:
*加密原语
*加密方案
*签名方案-附
*

在RSA wiki(https://en.wikipedia.org/wiki/RSA)上看到有如下描述:
RSA (cryptosystem), the Rivest-Shamir-Adleman cryptosystem, a cryptosystem for public-key encryption
从以上描述中可以看出RSA是一种公钥加密的密码系统。RSA也叫Rivest-Shamir-Adleman cryptosystem,由Ron Rivest, Adi Shamir和Leonard Adleman于MIT提出。RSA名称也是由Ron Rivest, Adi Shamir和Leonard Adleman三人名字中的首字母而来。

2 标记法

3 密钥类型
本文档中定义的原语和方案中使用了两种密钥类型:RSA公钥和RSA私钥。同时,RSA公钥和RSA私钥组成一个RSA密钥对。
该规范支持所谓的“多素数”("multi-prime")RSA,模数(modulus)可能有两个以上的素因子(prime factor)。

3.1 RSA公钥
RSA公钥由两个组件组成:
n RSA模数,一个正整数
e RSA公开(public)指数,一个正整数
一个有效的RSA公钥,RSA模数n为u个不同的奇素数(r_i,i = 1, 2, ..., u,u>=2, 如r_1, r_2, r_3, r_4, r_5,…,r_u。)的乘积。RSA公开(public)指数e是一个3到n-1之间的正整数,满足:
GCD(e,\lambda(n)) = 1

其中\lambda(n)=LCM(r_1 - 1, ..., r_u - 1),例如一组奇素数r_1, r_2, r_3, r_4, r_5,r_6, r_7为2、3、5、7、11、13、17,那么\lambda(n)为1,2,4,6,10,12,16的公倍数。

按照惯例,开始的两个素数r_1和r_2也可能分别由p和q指定。

素数又称质数(prime number),有无限个。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数
质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数的数称为质数。
如2、3、5、7、11、13、17都是些素数

GCD(greatest common divisor),最大公约数。
LCM(least common multiple),最小公倍数。

3.2 RSA私钥
一个RSA私钥可能有两种表示。
第一种表示由(n, d)对组成
n     RSA模数,一个正整数
d    RSA私有指数,一个正整数
第二种表示由一个5元组(p, q, dP, dQ, qInv)和一序列(可能为空)3元组(r_i, d_i, t_i)
组成。i = 3, ..., u,其中的每一个素数不会在5元组中出现。

p   首因子,一个正整数
q   次因子,一个正整数
dP  首因子的CRT指数,一个正整数
dQ  次因子的CRT指数,一个正整数
qInv  CRT系数(第一个),一个正整数
r_i   因子(第i个),一个正整数
d_i   因子(第i个)的CRT指数,一个正整数
t_i  因子(第i个)的CRT系数,一个正整数
对于第一种表示,一个有效的RSA私钥,RSA中的模数n和对应RSA公钥中的模数是相同的,并且模数n为u个不同的奇素数(r_i,i = 1, 2, ..., u,u>=2, 如r_1, r_2, r_3, r_4, r_5,…,r_u。)的乘积。RSA私有指数d是一个小于n的正整数,满足:

e * d == 1 (mod \lambda(n))

其中e是RSA公钥中的公开(public)指数,\lambda(n)的定义也和RSA公钥中定义的一样。

对于第二种表示,一个有效的RSA私钥,p和q这两个因子就是RSA模数n的开始两个素数因子(例如,r_1和r_2),CRT指数dP和dQ是一个分别小于p和q的正整数,满足:
e * dP == 1 (mod (p-1))
e * dQ == 1 (mod (q-1))

CRT系数qInv是一个小于p的正整数,满足:
q * qInv == 1 (mod p)

如果u>2, 这种表示将包含一个或多个3元组(r_i, d_i, t_i),i=3, ..., u。因子r_i就是RSA模数n额外的素数因子。每一个CRT指数d_i (i = 3, ..., u)满足:
e * d_i == 1 (mod (r_i - 1))

每一个CRT系数t_i (i = 3, ..., u)是一个小于r_i的正整数,满足:
R_i * t_i == 1 (mod r_i)
其中R_i = r_1 * r_2 * ... * r_(i-1)



4 数据转换原语
文档中定义的体系使用了两种数据转换原语。
I2OSP:Integer-to-Octet-String原语
OS2IP: Octet-String-to-Integer原语
4.1 I2OSP
I2OSP转换非负整数为一个指定长度的8位位组字符串(octet string)。

I2OSP (x, xLen)

输入:
x        将被转换的非负整数
xLen     返回的8位位组字符串(octet string)的长度。

输出:
X        对应的8位位组字符串(octet string),长度为xLen

错误: “传入的非负整数太大”




4.2 OS2IP

5 密码原语

5.1 加密解密原语
加密原语输入一个表示明文的整数,在指定公钥下加密输出一个表示密文的整数,解密原语是加密原语的逆过程,输入表示密文的整数,在指定对应的私钥下输出恢复原来的表示明文的整数。
文档中定义加密体系使用了一对加密解密原语:
RSAEP/RSADP
RSAEP和RSADP围绕相同的数学操作,只是输入的密钥不同,RSAEP输入的是公钥,RSADP输入的是私钥。
这里定义的原语和IEEE标准 1363-2000 [26]中IFEP-RSA/IFDP-RSA是一致的(除非新增了RSA多素数的支持),同时兼容PKCS #1 v1.5

这两个原语主要的数学操作就是求幂。

5.1.1 RSAEP

RSAEP(RSA Encryption primitives), RSA加密原语

RSAEP((n, e), m)

输入:
(n, e)  RSA公钥
m       信息描述,一个整数(0到n-1)

输出:
c       密文描述,一个整数(0到n-1)

错误:“信息描述超过了范围”

假定:RSA公钥(n, e)有效

步骤:
1、 如果信息描述m不在0到n-1之间,输出“信息描述超过了范围”并退出。
2、 对c作如下运算:c = m^e mod n
3、 输出c。

5.1.2 RSADP
RSADP(RSA Decryption primitives), RSA解密原语
RSADP (K, c)
输入:
K        RSA私钥,其中K可以是以下形式中的一个:
         - (n, d)对
         -一个5元组(p, q, dP, dQ, qInv)和一序列(可能为空)3元组(r_i, d_i, t_i), i = 3, ..., u
c        一个表示密文的整数,该整数在0到n-1之间。

输出:
m        一个表示明文的整数,该整数在0到n-1之间。
错误:“表示密文的整数超过了范围”

假定:RSA私钥K有效

步骤:
1、 如果表示密文的整数c不在0到n-1之间,输出“表示密文的整数超过了范围”并退出。
2、 对表示明文的整数m作如下运算:
a. 如果K使用的是第一种形式:(n, d)对,对m作如下运算:m = c^d mod n
b. 如果K使用的是第二种形式:一个5元组(p, q, dP, dQ, qInv)和一序列(可能为空)3元组(r_i, d_i, t_i), i = 3, ..., u,处理如下:
i. 赋值m_1 = c^dP mod p,以及m_2 = c^dQ mod q
ii. 如果u>2,赋值m_i = c^(d_i) mod r_i, i = 3, ..., u
iii. 赋值h = (m_1 - m_2) * qInv mod p
iv. 赋值m = m_2 + q * h
v. 如果u>2,赋值R = r_1,并且遍历i=3到u,执行:
1. 赋值R = R * r_(i-1)
2. 赋值h = (m_i - m) * t_i mod r_i
3. 赋值m = m + R * h
3、 输出m
5.2 签名和验证原语

6 方案概要

7 加密方案

7.1 RSAES-OAEP

7.2 RSAES-PKCS1-v1_5

8 签名方案-附

8.1 RSASSA-PSS

8.2 RSASSA-PKCS1-v1_5

9 签名的编码方式-附

9.1 EMSA-PSS

9.2 EMSA-PKCS1-v1_5

10 Openssl

10.1 DER

二进制DER编码
10.2 PEM

PEM stands for Privacy Enhanced Mail. PEM文件采用的是ASCII(Base64)编码,PEM文件使用Base64进行编码。

10.2.1 例子:PEM格式内容
-----BEGIN PRIVACY-ENHANCED MESSAGE-----
Proc-Type: 4,ENCRYPTED
Content-Domain: RFC822
DEK-Info: DES-CBC,F8143EDE5960C597
Originator-ID-Symmetric: [email protected],,
Recipient-ID-Symmetric: [email protected],ptf-kmc,3
Key-Info: DES-ECB,RSA-MD2,9FD3AAD2F2691B9A,
          B70665BB9BF7CBCDA60195DB94F727D3
Recipient-ID-Symmetric: [email protected],ptf-kmc,4
Key-Info: DES-ECB,RSA-MD2,161A3F75DC82EF26,
          E2EF532C65CBCFF79F83A2658132DB47

LLrHB0eJzyhP+/fSStdW8okeEnv47jxe7SJ/iN72ohNcUk2jHEUSoH1nvNSIWL9M
8tEjmF/zxB+bATMtPjCUWbz8Lr9wloXIkjHUlBLpvXR0UrUzYbkNpk0agV2IzUpk
J6UiRRGcDSvzrsoK+oNvqu6z7Xs5Xfz5rDqUcMlK1Z6720dcBWGGsDLpTpSCnpot
dXd/H5LMDWnonNvPCwQUHt==
-----END PRIVACY-ENHANCED MESSAGE-----




genrsa -out rsa_key.pem 1024

rsa -in rsa_key.pem -noout -text

genrsa -des -out rsa_key_endes.pem 1024

genrsa -des3 -out rsa_key_endes3.pem 1024

genrsa -aes128 -out rsa_key_enaes128.pem 1024


pkcs8 -topk8 -inform PEM -in rsa_key.pem -outform PEM -nocrypt -out key.pem


rsa -in rsa_key.pem -pubout -out rsa_public_key.pem

10.3 rsa_public_key.pem
假设生成的RSA公钥(rsa_public_key.pem文件)内容如下:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDW/XkRFZ+FtYB3bfHYnRoLyRIm
ch4+6ymFh3K8O9Cbb0HZg64MLi3lnyW3zoqMWjUI5aszCoZ2duqNy/BSBFtmuBGn
OK6i6QWmPZu+c8NpfVbWe5GxWXg/yeaYv5GlpA2hBlnDw3UDUdl6pyZyUH+PAN5i
yQwAq7JjDh8p9V4G9QIDAQAB
-----END PUBLIC KEY-----

10.3.1 PEM文件解析

typedef void bio_info_cb(struct bio_st *, int, const char *, int, long, long);

struct crypto_ex_data_st
{
STACK_OF(void) *sk;
int dummy; /* gcc is screwing up this data structure :-( */
};

typedef struct crypto_ex_data_st CRYPTO_EX_DATA;


struct bio_st
{
BIO_METHOD *method;
/* bio, mode, argp, argi, argl, ret */
long (*callback)(struct bio_st *,int,const char *,int, long,long);
char *cb_arg; /* first argument for the callback */

int init;
int shutdown;
int flags; /* extra storage */
int retry_reason;
int num;
void *ptr;
struct bio_st *next_bio; /* used by filter BIOs */
struct bio_st *prev_bio; /* used by filter BIOs */
int references;
unsigned long num_read;
unsigned long num_write;

CRYPTO_EX_DATA ex_data;
};


typedef struct bio_st BIO;


typedef struct bio_method_st
{
int type;
const char *name;
int (*bwrite)(BIO *, const char *, int);
int (*bread)(BIO *, char *, int);
int (*bputs)(BIO *, const char *);
int (*bgets)(BIO *, char *, int);
long (*ctrl)(BIO *, int, long, void *);
int (*create)(BIO *);
int (*destroy)(BIO *);
        long (*callback_ctrl)(BIO *, int, bio_info_cb *);
} BIO_METHOD;

static int MS_CALLBACK file_gets(BIO *bp, char *buf, int size)
{
int ret=0;

buf[0]='\0';
if (bp->flags&BIO_FLAGS_UPLINK)
{
if (!UP_fgets(buf,size,bp->ptr))
goto err;
}
else
{
if (!fgets(buf,size,(FILE *)bp->ptr))
goto err;
}
if (buf[0] != '\0')
ret=strlen(buf);
err:
return(ret);
}


static BIO_METHOD methods_filep=
{
BIO_TYPE_FILE,
"FILE pointer",
file_write,
file_read,
file_puts,
file_gets,
file_ctrl,
file_new,
file_free,
NULL,
};

BIO_METHOD *BIO_s_file(void)
{
return(&methods_filep);
}

BIO *BIO_new(BIO_METHOD *method)
{
BIO *ret=NULL;

ret=(BIO *)OPENSSL_malloc(sizeof(BIO));
if (ret == NULL)
{
BIOerr(BIO_F_BIO_NEW,ERR_R_MALLOC_FAILURE);
return(NULL);
}
if (!BIO_set(ret,method))
{
OPENSSL_free(ret);
ret=NULL;
}
return(ret);
}

long BIO_ctrl(BIO *b, int cmd, long larg, void *parg)
{
long ret;
long (*cb)(BIO *,int,const char *,int,long,long);

if (b == NULL) return(0);

if ((b->method == NULL) || (b->method->ctrl == NULL))
{
BIOerr(BIO_F_BIO_CTRL,BIO_R_UNSUPPORTED_METHOD);
return(-2);
}

cb=b->callback;

if ((cb != NULL) &&
((ret=cb(b,BIO_CB_CTRL,parg,cmd,larg,1L)) <= 0))
return(ret);

ret=b->method->ctrl(b,cmd,larg,parg);

if (cb != NULL)
ret=cb(b,BIO_CB_CTRL|BIO_CB_RETURN,parg,cmd,
larg,ret);
return(ret);
}


#define BIO_set_fp(b,fp,c) BIO_ctrl(b,BIO_C_SET_FILE_PTR,c,(char *)fp)

int BIO_gets(BIO *b, char *in, int inl)
{
int i;
long (*cb)(BIO *,int,const char *,int,long,long);

if ((b == NULL) || (b->method == NULL) || (b->method->bgets == NULL))
{
BIOerr(BIO_F_BIO_GETS,BIO_R_UNSUPPORTED_METHOD);
return(-2);
}

cb=b->callback;

if ((cb != NULL) &&
((i=(int)cb(b,BIO_CB_GETS,in,inl,0L,1L)) <= 0))
return(i);

if (!b->init)
{
BIOerr(BIO_F_BIO_GETS,BIO_R_UNINITIALIZED);
return(-2);
}

i=b->method->bgets(b,in,inl);

if (cb != NULL)
i=(int)cb(b,BIO_CB_GETS|BIO_CB_RETURN,in,inl,
0L,(long)i);
return(i);
}


int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
     long *len)
{
EVP_ENCODE_CTX ctx;
int end=0,i,k,bl=0,hl=0,nohead=0;
char buf[256];
BUF_MEM *nameB;
BUF_MEM *headerB;
BUF_MEM *dataB,*tmpB;

nameB=BUF_MEM_new();
headerB=BUF_MEM_new();
dataB=BUF_MEM_new();
if ((nameB == NULL) || (headerB == NULL) || (dataB == NULL))
{
BUF_MEM_free(nameB);
BUF_MEM_free(headerB);
BUF_MEM_free(dataB);
PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE);
return(0);
}

buf[254]='\0';
for (;;)
{
i=BIO_gets(bp,buf,254);

if (i <= 0)
{
PEMerr(PEM_F_PEM_READ_BIO,PEM_R_NO_START_LINE);
goto err;
}

while ((i >= 0) && (buf[i] <= ' ')) i--;
buf[++i]='\n'; buf[++i]='\0';

if (strncmp(buf,"-----BEGIN ",11) == 0)
{
i=strlen(&(buf[11]));

if (strncmp(&(buf[11+i-6]),"-----\n",6) != 0)
continue;
if (!BUF_MEM_grow(nameB,i+9))
{
PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE);
goto err;
}
memcpy(nameB->data,&(buf[11]),i-6);
nameB->data[i-6]='\0';
break;
}
}
hl=0;
if (!BUF_MEM_grow(headerB,256))
{ PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE); goto err; }
headerB->data[0]='\0';
for (;;)
{
i=BIO_gets(bp,buf,254);
if (i <= 0) break;

while ((i >= 0) && (buf[i] <= ' ')) i--;
buf[++i]='\n'; buf[++i]='\0';

if (buf[0] == '\n') break;
if (!BUF_MEM_grow(headerB,hl+i+9))
{ PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE); goto err; }
if (strncmp(buf,"-----END ",9) == 0)
{
nohead=1;
break;
}
memcpy(&(headerB->data[hl]),buf,i);
headerB->data[hl+i]='\0';
hl+=i;
}

bl=0;
if (!BUF_MEM_grow(dataB,1024))
{ PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE); goto err; }
dataB->data[0]='\0';
if (!nohead)
{
for (;;)
{
i=BIO_gets(bp,buf,254);
if (i <= 0) break;

while ((i >= 0) && (buf[i] <= ' ')) i--;
buf[++i]='\n'; buf[++i]='\0';

if (i != 65) end=1;
if (strncmp(buf,"-----END ",9) == 0)
break;
if (i > 65) break;
if (!BUF_MEM_grow_clean(dataB,i+bl+9))
{
PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE);
goto err;
}
memcpy(&(dataB->data[bl]),buf,i);
dataB->data[bl+i]='\0';
bl+=i;
if (end)
{
buf[0]='\0';
i=BIO_gets(bp,buf,254);
if (i <= 0) break;

while ((i >= 0) && (buf[i] <= ' ')) i--;
buf[++i]='\n'; buf[++i]='\0';

break;
}
}
}
else
{
tmpB=headerB;
headerB=dataB;
dataB=tmpB;
bl=hl;
}
i=strlen(nameB->data);
if ( (strncmp(buf,"-----END ",9) != 0) ||
(strncmp(nameB->data,&(buf[9]),i) != 0) ||
(strncmp(&(buf[9+i]),"-----\n",6) != 0))
{
PEMerr(PEM_F_PEM_READ_BIO,PEM_R_BAD_END_LINE);
goto err;
}

EVP_DecodeInit(&ctx);
i=EVP_DecodeUpdate(&ctx,
(unsigned char *)dataB->data,&bl,
(unsigned char *)dataB->data,bl);
if (i < 0)
{
PEMerr(PEM_F_PEM_READ_BIO,PEM_R_BAD_BASE64_DECODE);
goto err;
}
i=EVP_DecodeFinal(&ctx,(unsigned char *)&(dataB->data[bl]),&k);
if (i < 0)
{
PEMerr(PEM_F_PEM_READ_BIO,PEM_R_BAD_BASE64_DECODE);
goto err;
}
bl+=k;

if (bl == 0) goto err;
*name=nameB->data;
*header=headerB->data;
*data=(unsigned char *)dataB->data;
*len=bl;
OPENSSL_free(nameB);
OPENSSL_free(headerB);
OPENSSL_free(dataB);
return(1);
err:
BUF_MEM_free(nameB);
BUF_MEM_free(headerB);
BUF_MEM_free(dataB);
return(0);
}


int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
     long *len)
        {
        BIO *b;
        int ret;

        if ((b=BIO_new(BIO_s_file())) == NULL)
{
PEMerr(PEM_F_PEM_READ,ERR_R_BUF_LIB);
                return(0);
}
        BIO_set_fp(b,fp,BIO_NOCLOSE);
        ret=PEM_read_bio(b, name, header, data,len);
        BIO_free(b);
        return(ret);
        }

附录 A ASN.1语法

A.1 RSA 密钥描述

A.1.1 RSA 公钥语法

RSAPublicKey ::= SEQUENCE {
modulus           INTEGER,  -- n
publicExponent    INTEGER   -- e
}

A.1.2 RSA 私钥语法

RSAPrivateKey ::= SEQUENCE {
version           Version,
modulus           INTEGER,  -- n
publicExponent    INTEGER,  -- e
privateExponent   INTEGER,  -- d
prime1            INTEGER,  -- p
prime2            INTEGER,  -- q
exponent1         INTEGER,  -- d mod (p-1)
exponent2         INTEGER,  -- d mod (q-1)
coefficient       INTEGER,  -- (inverse of q) mod p
otherPrimeInfos   OtherPrimeInfos OPTIONAL
}


A.2 体系验证




1、 PKCS #1: RSA Encryption Version 1.5,https://www.rfc-editor.org/rfc/rfc2313.txt
2、 PKCS #1: RSA Cryptography Specifications Version 2.0,https://www.ietf.org/rfc/rfc2437.txt
3、 Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1,https://www.rfc-editor.org/rfc/rfc3447.txt
4、 https://people.cs.umass.edu/~emery/classes/cmpsci691st/scribe/lecture14-rsa.pdf
5、 https://en.wikipedia.org/wiki/RSA_(cryptosystem)
6、 https://en.wikipedia.org/wiki/RSA
7、 PEM, Privacy Enhancement for Internet Electronic Mail: Part I: Message Encipherment and Authentication Procedures, https://www.rfc-editor.org/rfc/rfc1040.txt
8、 PEM, Privacy Enhancement for Internet Electronic Mail: Part I -- Message Encipherment and Authentication Procedures, https://www.rfc-editor.org/rfc/rfc1113.txt
9、 PEM,Privacy Enhancement for Internet Electronic Mail: Part I: Message Encryption and Authentication Procedures,https://www.rfc-editor.org/rfc/rfc1421.txt
10、 PEM, Privacy Enhancement for Internet Electronic Mail: Part II: Certificate-Based Key Management, https://www.rfc-editor.org/rfc/rfc1422.txt
11、 PEM, Privacy Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, and Identifiers, https://www.rfc-editor.org/rfc/rfc1423.txt
12、 PEM, Privacy Enhancement for Internet Electronic Mail: Part IV: Key Certification and Related Services, https://www.rfc-editor.org/rfc/rfc1424.txt

猜你喜欢

转载自lobin.iteye.com/blog/2328267