RSA
Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1
目录
1介绍3
2标记法3
3密钥类型4
3.1RSA公钥4
3.2RSA私钥5
4数据转换原语6
4.1I2OSP6
4.2OS2IP7
5密码原语7
5.1加密解密原语7
5.1.1RSAEP7
5.1.2RSADP7
5.2签名和验证原语8
6方案概要8
7加密方案8
7.1RSAES-OAEP8
7.2RSAES-PKCS1-v1_58
8签名方案-附8
8.1RSASSA-PSS8
8.2RSASSA-PKCS1-v1_58
9签名的编码方式-附9
9.1EMSA-PSS9
9.2EMSA-PKCS1-v1_59
10Openssl9
10.1DER9
10.2PEM9
10.2.1例子:PEM格式内容9
10.3rsa_public_key.pem10
10.3.1PEM文件解析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.1RSA公钥
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.2RSA私钥
一个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.1I2OSP
I2OSP转换非负整数为一个指定长度的8位位组字符串(octet string)。
I2OSP (x, xLen)
输入:
x 将被转换的非负整数
xLen 返回的8位位组字符串(octet string)的长度。
输出:
X 对应的8位位组字符串(octet string),长度为xLen
错误: “传入的非负整数太大”
4.2OS2IP
5密码原语
5.1加密解密原语
加密原语输入一个表示明文的整数,在指定公钥下加密输出一个表示密文的整数,解密原语是加密原语的逆过程,输入表示密文的整数,在指定对应的私钥下输出恢复原来的表示明文的整数。
文档中定义加密体系使用了一对加密解密原语:
RSAEP/RSADP
RSAEP和RSADP围绕相同的数学操作,只是输入的密钥不同,RSAEP输入的是公钥,RSADP输入的是私钥。
这里定义的原语和IEEE标准 1363-2000 [26]中IFEP-RSA/IFDP-RSA是一致的(除非新增了RSA多素数的支持),同时兼容PKCS #1 v1.5
这两个原语主要的数学操作就是求幂。
5.1.1RSAEP
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.2RSADP
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.1RSAES-OAEP
7.2RSAES-PKCS1-v1_5
8签名方案-附
8.1RSASSA-PSS
8.2RSASSA-PKCS1-v1_5
9签名的编码方式-附
9.1EMSA-PSS
9.2EMSA-PKCS1-v1_5
10Openssl
10.1DER
二进制DER编码
10.2PEM
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.3rsa_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.1PEM文件解析
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 体系验证
Java RSA加密解密实例
private static RSAPrivateKey privateKey = null; private static byte[] privateKeyEncoded = null; private static RSAPublicKey publicKey = null; private static byte[] publicKeyEncoded = null; @BeforeClass public static void init() /* throws NoSuchAlgorithmException */ { KeyPairGenerator keyPairGenerator = null; try { keyPairGenerator = KeyPairGenerator.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } keyPairGenerator.initialize(512); KeyPair keyPair = keyPairGenerator.generateKeyPair(); privateKey = (RSAPrivateKey) keyPair.getPrivate(); publicKey = (RSAPublicKey) keyPair.getPublic(); privateKeyEncoded = ((Key) privateKey).getEncoded(); publicKeyEncoded = ((Key) publicKey).getEncoded(); System.out.println("private key: " + Base64.byteArrayToBase64(privateKeyEncoded)); System.out.println("public key: " + Base64.byteArrayToBase64(publicKeyEncoded)); }
加密解密
@org.junit.Test public void test() { String message = "13120983870"; System.out.println(message); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyEncoded); KeyFactory keyFactory = null; try { keyFactory = KeyFactory.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } PrivateKey privateKey = null; try { privateKey = keyFactory.generatePrivate(pkcs8KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("private key: " + Base64.byteArrayToBase64(((Key) privateKey).getEncoded())); Cipher cipher = null; try { cipher = Cipher.getInstance(keyFactory.getAlgorithm()); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } catch (NoSuchPaddingException e) { Assert.fail("no such padding: " + e.getMessage()); } try { cipher.init(Cipher.ENCRYPT_MODE, privateKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] encryption = null; try { encryption = cipher.doFinal(message.getBytes()); } catch (IllegalBlockSizeException e) { Assert.fail("illegal block size: " + e.getMessage()); } catch (BadPaddingException e) { Assert.fail("bad padding: " + e.getMessage()); } System.out.println("encryption: " + Base64.byteArrayToBase64(encryption)); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyEncoded); try { keyFactory = KeyFactory.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } PublicKey publicKey = null; try { publicKey = keyFactory.generatePublic(x509KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("public key: " + Base64.byteArrayToBase64(((Key) publicKey).getEncoded())); try { cipher = Cipher.getInstance(keyFactory.getAlgorithm()); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } catch (NoSuchPaddingException e) { Assert.fail("no such padding: " + e.getMessage()); } try { cipher.init(Cipher.DECRYPT_MODE, publicKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] decryption = null; try { decryption = cipher.doFinal(encryption); } catch (IllegalBlockSizeException e) { Assert.fail("illegal block size: " + e.getMessage()); } catch (BadPaddingException e) { Assert.fail("bad padding: " + e.getMessage()); } System.out.println("decryption: " + new String(decryption) + ", base64:" + Base64.byteArrayToBase64(decryption)); }
/** * 使用私钥加密,再使用公钥解密 */ @org.junit.Test public void test1() { String message = "13120983870"; System.out.println(message); // 加密 Cipher cipher = null; try { cipher = Cipher.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } catch (NoSuchPaddingException e) { Assert.fail("no such padding: " + e.getMessage()); } try { cipher.init(Cipher.ENCRYPT_MODE, privateKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] encryption = null; try { encryption = cipher.doFinal(message.getBytes()); } catch (IllegalBlockSizeException e) { Assert.fail("illegal block size: " + e.getMessage()); } catch (BadPaddingException e) { Assert.fail("bad padding: " + e.getMessage()); } System.out.println("encryption: " + Base64.byteArrayToBase64(encryption)); // 解密 try { cipher = Cipher.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } catch (NoSuchPaddingException e) { Assert.fail("no such padding: " + e.getMessage()); } try { cipher.init(Cipher.DECRYPT_MODE, publicKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] decryption = null; try { decryption = cipher.doFinal(encryption); } catch (IllegalBlockSizeException e) { Assert.fail("illegal block size: " + e.getMessage()); } catch (BadPaddingException e) { Assert.fail("bad padding: " + e.getMessage()); } System.out.println("decryption: " + new String(decryption) + ", base64:" + Base64.byteArrayToBase64(decryption)); }
private key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAhLKv2wOrV2BGqXxRyrLSJ6jzMey1kxuthXFO+EBjiI7GuTxYpr6lXxyrfnwuhBz0OrXS4QatE9PT2JudFWMsSQIDAQABAkBSNtM1goR50jB1eYzDZR9Haymh2OJ2jkNn1dfzfxEr3UTjlhv42v7FfmLWl0TISEuW5AxZyZBFHhWP7YNF3RYBAiEAxRixL6dmIpRxndVxcCvml16Cn3J+NDkRyWmzwS0WyXECIQCsWwu6+P88wUEOFTgQ/Z5EQFkCXm5h6dL/EmhUordkWQIgTCvuzmvznQmhn04OOTu+MmHkOZsWCzjDFwQy5EV4uQECIEwTN79EbmxjpJJRvViKiVP4zxDjm3cuXQpnFpPc6nOpAiAEiLzfZvzCI4Vx3KxGrOLxaTWC9KbpCG3IRsLBMN/EqA== public key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAISyr9sDq1dgRql8Ucqy0ieo8zHstZMbrYVxTvhAY4iOxrk8WKa+pV8cq358LoQc9Dq10uEGrRPT09ibnRVjLEkCAwEAAQ== 13120983870 encryption: ZVT1Gt5cP/KHmogMcWU0TxLm1hYqRXzqsvLCvQr9pDgjVA+yzXM6IWZSdXf2dm+j9XeGS72bHayOIo7Py+tEbQ== decryption: 13120983870, base64:MTMxMjA5ODM4NzA=
Java RSA数字签名实例
/** * private key: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApTHMs+zR16SE0v3npoVbMGo70xX5tJ7HF23SvM2rARkJNtRs4xZRQpWQ1JBZnGna9HcVQsrRAORqYhhTrZ9rMQIDAQABAkAFNrlYrasZErJGQEEiIWP9lwHCvZchLTB4j+TahIV+2iLTiLa21QOqQFmpBqw/uqmHsJGtqtHIXdtgCrGtoLVhAiEA4zpbZ52vkCskvZ2eJ34n6dTsiybZLIMYIdp21kd6mpECIQC6HJ2f0R6BwL/ORYhF6tA1YeXZEKyAuTgDkwgmGN/WoQIgPsXrZHeafbB9iOiXPX/LlPyekF6eFn7s1sVcmRvMEhECIBnJDS2vU4K2qdxyVccaGW7L+YRxgvTytIgKPv7IQ3sBAiEAh3XrxyuR3nJhFD5pPcRLmnst9Ag6WQuthc/SgkKJlXk= * public key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKUxzLPs0dekhNL956aFWzBqO9MV+bSexxdt0rzNqwEZCTbUbOMWUUKVkNSQWZxp2vR3FULK0QDkamIYU62fazECAwEAAQ== */ @Test public void signAndVerityWithEncoded0() { String privateKey = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApTHMs+zR16SE0v3npoVbMGo70xX5tJ7HF23SvM2rARkJNtRs4xZRQpWQ1JBZnGna9HcVQsrRAORqYhhTrZ9rMQIDAQABAkAFNrlYrasZErJGQEEiIWP9lwHCvZchLTB4j+TahIV+2iLTiLa21QOqQFmpBqw/uqmHsJGtqtHIXdtgCrGtoLVhAiEA4zpbZ52vkCskvZ2eJ34n6dTsiybZLIMYIdp21kd6mpECIQC6HJ2f0R6BwL/ORYhF6tA1YeXZEKyAuTgDkwgmGN/WoQIgPsXrZHeafbB9iOiXPX/LlPyekF6eFn7s1sVcmRvMEhECIBnJDS2vU4K2qdxyVccaGW7L+YRxgvTytIgKPv7IQ3sBAiEAh3XrxyuR3nJhFD5pPcRLmnst9Ag6WQuthc/SgkKJlXk="; String publicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKUxzLPs0dekhNL956aFWzBqO9MV+bSexxdt0rzNqwEZCTbUbOMWUUKVkNSQWZxp2vR3FULK0QDkamIYU62fazECAwEAAQ=="; byte[] privateKeyEncoded = Base64.base64ToByteArray(privateKey); byte[] publicKeyEncoded = Base64.base64ToByteArray(publicKey); String message = "13120983870"; System.out.println(message); signAndVerity(message, privateKeyEncoded, publicKeyEncoded); }
private void signAndVerity(String message, byte[] privateKeyEncoded, byte[] publicKeyEncoded) { // 签名 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyEncoded); KeyFactory keyFactory = null; try { keyFactory = KeyFactory.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } PrivateKey privateKey = null; try { privateKey = keyFactory.generatePrivate(pkcs8KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("private key: " + Base64.byteArrayToBase64(((Key) privateKey).getEncoded())); Signature signature = null; try { signature = Signature.getInstance("MD5withRSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } try { signature.initSign(privateKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] sign = null; try { signature.update(message.getBytes()); sign = signature.sign(); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } System.out.println("signature: " + Base64.byteArrayToBase64(sign)); // 验证 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyEncoded); try { keyFactory = KeyFactory.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { Assert.fail("no such algorithm: " + e.getMessage()); } PublicKey publicKey = null; try { publicKey = keyFactory.generatePublic(x509KeySpec); } catch (InvalidKeySpecException e) { Assert.fail("invalid key spec: " + e.getMessage()); } System.out.println("public key: " + Base64.byteArrayToBase64(((Key) publicKey).getEncoded())); try { signature.initVerify(publicKey); } catch (InvalidKeyException e) { Assert.fail("invalid key: " + e.getMessage()); } byte[] decryption = null; try { signature.update(message.getBytes()); boolean result = signature.verify(sign); Assert.assertTrue(result); } catch (SignatureException e) { Assert.fail("signature: " + e.getMessage()); } }
private key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA36Luv7yDI5RCnvC/d8HFvqXHa5Iry2bBX1qDo2KQkzlMzr5mVnMCk3WOA49PVyQ9EPJa7kIrfRlSdp38R3FB1wIDAQABAkA5nUxM8VAHtoaDVBq/y5gaSbNar0nBGTPwUO1hBl+gzcMGgPEw4F1DaYelt+dUxbD7po4OPiiHz/F5+HJAV5SBAiEA72yOz+HfhCqkvQ5l4dSIpoSmfcw05CxnMBe2p+FtskcCIQDvHpAGQ8po0l0NIgyK+bUIuuHDOUb5ePWtiA4kSrGr8QIgWfgONlnndy/bFdv6NwF5lDFWqwD4gyGYaP8QOUfBw/MCIBQJx5/+xlOKbWnQVKTA0D7vCkRF5IC7djsYj7bS25jBAiAS/IX4KRsV9TayXXDeuqaD8Z+ONQ/98xJwAabcNAmXrA== public key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAN+i7r+8gyOUQp7wv3fBxb6lx2uSK8tmwV9ag6NikJM5TM6+ZlZzApN1jgOPT1ckPRDyWu5CK30ZUnad/EdxQdcCAwEAAQ== 13120983870 private key: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApTHMs+zR16SE0v3npoVbMGo70xX5tJ7HF23SvM2rARkJNtRs4xZRQpWQ1JBZnGna9HcVQsrRAORqYhhTrZ9rMQIDAQABAkAFNrlYrasZErJGQEEiIWP9lwHCvZchLTB4j+TahIV+2iLTiLa21QOqQFmpBqw/uqmHsJGtqtHIXdtgCrGtoLVhAiEA4zpbZ52vkCskvZ2eJ34n6dTsiybZLIMYIdp21kd6mpECIQC6HJ2f0R6BwL/ORYhF6tA1YeXZEKyAuTgDkwgmGN/WoQIgPsXrZHeafbB9iOiXPX/LlPyekF6eFn7s1sVcmRvMEhECIBnJDS2vU4K2qdxyVccaGW7L+YRxgvTytIgKPv7IQ3sBAiEAh3XrxyuR3nJhFD5pPcRLmnst9Ag6WQuthc/SgkKJlXk= signature: YVuyrhVPkQhydhWWe9+TMAPnDCRVpy3mM0Q2tDQsWhJTOntYlH7t7/ENj76flzOmXr6zSfNZX6Qnh2SbRQkm+Q== public key: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKUxzLPs0dekhNL956aFWzBqO9MV+bSexxdt0rzNqwEZCTbUbOMWUUKVkNSQWZxp2vR3FULK0QDkamIYU62fazECAwEAAQ==
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