PEM OpenSSL 和许多其他 SSL 工具的标准格式, OpenSSL 使用 PEM 文件格式存储证书和密钥。这种格式被设计用来安全的包含在 ascii 甚至富文本文档中,如电子邮件。这意味着您可以简单的复制和粘贴 pem 文件的内容到另一个文档中。

PEM 文件 Base64 编码的证书。 PEM 证书通常用于 web 服务器,因为他们可以通过一个简单的文本编辑器,很容易地转换成可读的数据。通常当一个 PEM 编码在文本编辑器中打开文件 , 它会包含不同的页眉和页脚。

-----BEGIN CERTIFICATE REQUEST----- and -----END CERTIFICATEREQUEST-----

CSR( 证书签名请求 )

-----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATEKEY-----

-----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----

PKCS #8: Private-Key Information Syntax(语法) Standard(标准)

OpenSSL: 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的 密钥 和证书封装管理功能及 SSL 协议,并提供丰富的 应用程序 供测试或其它目的使用。

OpenSSL 整个软件包大概可以分成三个主要的功能部分:密码算法库、 SSL 协议库以及应用程序。 OpenSSL 的目录结构自然也是围绕这三个功能部分进行规划的。

一、OpenSSL生成pem格式公私钥

1、生成RSA私钥

openssl genrsa -out rsa_private_key.pem1024

该命令会生成 1024 位的私钥,运行,如下图:

生成私钥文件 rsa_private_key.pem ,内容如下:

用记事本方式打开它,可以看到 -----BEGIN RSA PRIVATE KEY----- 开头, -----END RSA PRIVATE KEY----- 结尾的字符串,这个就是原始的私钥。

若运行openssl.exe,会进入OpenSSL命令行界面,此时输入命令时,则无需再写 openssl 。(只是该命令行界面中,暂时无法拷贝,本人太懒,不太喜欢)

2、RSA私钥转换成PKCS8格式

openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem-outform PEM - nocrypt

可以看到,控制台打印出的内容, -----BEGIN PRIVATE KEY----- 开头, -----END PRIVATE KEY----- 结尾的字符串,这个就是 PKCS#8 格式的私钥。

使用该命令,将私钥转成 PKCS#8 格式 ,但原 rsa_private_key.pem 文件中的私钥字符串并没有任何变化。但控制台输出的 private key ,跟 rsa_private_key.pem 文件中的 private key ,不一样。 若需使用 PKCS8 格式的私钥,即控制台中显示的私钥,将其拷贝出来即可。

opensslpkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM nocrypt

“-” 书写正确,上述 nocrypt ,因为前面的 不是英文的,导致 nocrypt 失效,所以还需要输入密码 。需要输入两次密码,运行,如下图:

可以看到,控制台打印出的内容, -----BEGIN ENCRYPTED PRIVATE KEY----- 开头, -----END ENCRYPTED PRIVATE KEY----- 结尾的字符串,这个就是加了密的 PKCS#8 格式的私钥。

因为输入了密码,转换后的字符串不一样,会比加了 - nocrypt 的长一些,所以原来的程序解析不了该私钥字符串,会出错。

3、生成RSA公钥

openssl rsa -in rsa_private_key.pem-pubout -out rsa_public_key.pem

运行,如下图:

生成公钥文件 rsa_public_key.pem 内容如下:

用记事本方式打开它,可以看到 -----BEGIN PUBLIC KEY----- 开头, -----END PUBLIC KEY----- 结尾的字符串,这个就是公钥。

4、Java使用pem文件内容,示例代码

1)私钥签名

a )获取私钥

// 获取 KeyFactory ,指定 RSA 算法

KeyFactorykeyFactory = KeyFactory. getInstance ( "RSA" );

// BASE64 编码的私钥字符串进行解码

BASE64Decoderdecoder = new BASE64Decoder();

byte [] encodeByte = decoder.decodeBuffer(priKey);

// BASE64 解码后的字节数组,构造成 PKCS8EncodedKeySpec 对象,生成私钥对象

PrivateKeyprivatekey = keyFactory.generatePrivate( new PKCS8EncodedKeySpec(encodeByte));

b )使用私钥,对数据进行签名

// 获取 Signature 实例,指定签名算法(本例使用 SHA1WithRSA

Signaturesignature = Signature. getInstance ( "SHA1WithRSA" );

// 加载 私钥

signature.initSign(privatekey);

// 更新 待签名的数据

signature.update(plain.getBytes( "UTF-8" ));

/ / 进行签名

byte [] signed = signature.sign();

// 将加密后的字节数组,转换成 BASE64 编码的字符串,作为最终的签名数据

BASE64Encoderencoder = new BASE64Encoder();

return encoder.encode(signed);

2)公钥验签

a )获取公钥

// 获取 KeyFactory ,指定 RSA 算法

KeyFactorykeyFactory = KeyFactory. getInstance ( "RSA" );

// BASE64 编码的公钥字符串进行解码

BASE64Decoderdecoder = new BASE64Decoder();

byte [] encodeByte = decoder.decodeBuffer(pubKey);

// BASE64 解码后的字节数组,构造成 X509EncodedKeySpec 对象,生成公钥对象

PublicKeypublicKey = keyFactory.generatePublic( new X509EncodedKeySpec(encodeByte));

b )使用公钥,进行验签

// 获取 Signature 实例,指定签名算法 ( 与之前一致 )

Signaturesignature = Signature. getInstance ( "SHA1WithRSA" );

// 加载公钥

signature.initVerify(publicKey);

// 更新 原数据

signature.update(plain.getBytes( "UTF-8" ));

// 公钥验签( true- 验签通过; false- 验签失败)

BASE64Decoderdecoder = new BASE64Decoder();

return signature.verify(decoder.decodeBuffer(sign));

验签时,签名数据需要先 BASE64 解码

转载自:https://www.cnblogs.com/vicent/p/3805722.html 1.使用openssl 生成 私钥和公钥 openssl下载地址:http://www.openssl.org/source openssl 生成 私钥命令: gen rsa -out rsa _private_key. pem 1024 openssl 生成 公钥命令: rsa -in rsa _private_...
通过openssl工具 生成 RSA 的公钥和私钥(opnssl工具可在互联网中下载到)1) 生成 RSA 私钥 打开 bin 文件 夹下面的openssl.exe, 打开 生成 命令.txt 文件 ,输入“ 生成 命令.txt” 文件 中 gen rsa -out rsa _private_key. pem 1024,并回车 得到 生成 成功的结果,如下图: 此时,我们可以在bin 文件 夹中看到一个 文件 名为 rsa _private_key....
由于我用的一直是MAC系统,没有关注过windows对 pem 文件 的访问,今天教同事使用『私钥』访问远程服务,她的是windows 7的系统,但是她机器上装的xshell工具过期了。我就说用其他工具吧。    悲剧就开始了,我当时忽略了windows和mac的系统区别,直接在putty工具上用了ssh使用 密钥 链接的命令(习惯了),然后就尴尬了,连不上,我想了好久为啥,之后了解到putty的密...
// 将 密钥 对写入 文件 bp_public = BIO_new_file(pubkeyfile, "w+"); ret = PEM _write_bio_ RSA PublicKey(bp_public, r); if (ret != 1) { goto finish; bp_private = BIO_new_file(privkeyfile, "w+"); ret = PEM _write_bio_ RSA PrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL); if (ret != 1) { goto finish; finish: if (r) { RSA _free(r); if (bne) { BN_free(bne); if (bp_public) { BIO_free_all(bp_public); if (bp_private) { BIO_free_all(bp_private); return ret; SM2Sig 函数: ```c++ #include <openssl/bn.h> #include <openssl/ec.h> #include <openssl/evp.h> #include <openssl/rand.h> #include <openssl/sm2.h> int SM2Sig(const unsigned char *msg, size_t msglen, const char *privkeyfile, unsigned char *sig, size_t *siglen) int ret = 0; EC_KEY *ec_key = NULL; EVP_MD_CTX *md_ctx = NULL; unsigned char dgst[32]; size_t dgstlen; const EVP_MD *md; BIGNUM *k = NULL; EC_POINT *P = NULL; // 读取 私钥 ec_key = EC_KEY_new_by_curve_name(NID_sm2); if (!ec_key) { goto finish; FILE *fp = fopen(privkeyfile, "r"); if (!fp) { goto finish; PEM _read_ECPrivateKey(fp, &ec_key, NULL, NULL); fclose(fp); fp = NULL; // 计算消息摘要 md = EVP_sm3(); md_ctx = EVP_MD_CTX_new(); EVP_DigestInit_ex(md_ctx, md, NULL); EVP_DigestUpdate(md_ctx, msg, msglen); EVP_DigestFinal_ex(md_ctx, dgst, &dgstlen); EVP_MD_CTX_free(md_ctx); md_ctx = NULL; // 生成 随机数 k k = BN_new(); ret = BN_rand_range(k, EC_GROUP_order(EC_KEY_get0_group(ec_key))); if (ret != 1) { goto finish; // 计算椭圆曲线点 P = [k]G P = EC_POINT_new(EC_KEY_get0_group(ec_key)); ret = EC_POINT_mul(EC_KEY_get0_group(ec_key), P, k, NULL, NULL, NULL); if (ret != 1) { goto finish; // 计算 r = (e + x1) mod n BIGNUM *r = BN_new(); const EC_POINT *pubkey = EC_KEY_get0_public_key(ec_key); EC_POINT_get_affine_coordinates(EC_KEY_get0_group(ec_key), pubkey, r, NULL, NULL); BN_add(r, r, dgst); BN_mod(r, r, EC_GROUP_order(EC_KEY_get0_group(ec_key)), NULL); // 计算 s = ((1 + dA)^-1 * (k - r * dA)) mod n BIGNUM *s = BN_new(); BIGNUM *dA = BN_new(); const BIGNUM *privkey = EC_KEY_get0_private_key(ec_key); BN_copy(dA, privkey); BN_mod_add(dA, dA, EC_GROUP_order(EC_KEY_get0_group(ec_key)), EC_GROUP_order(EC_KEY_get0_group(ec_key)), NULL); BN_add_word(dA, 1); BN_mod_inverse(dA, dA, EC_GROUP_order(EC_KEY_get0_group(ec_key)), NULL); BN_mul(s, r, privkey, NULL); BN_sub(s, k, s); BN_mod_mul(s, s, dA, EC_GROUP_order(EC_KEY_get0_group(ec_key)), NULL); // 将 r 和 s 拼接成签名数据 unsigned char *p = sig; *p++ = 0x30; p++; // 后面填充长度 unsigned char *rpos = p; *p++ = 0x02; if (BN_num_bits(r) % 8 == 0) { *p++ = BN_num_bits(r) / 8; } else { *p++ = BN_num_bits(r) / 8 + 1; BN_bn2bin(r, p); p += *rpos + 1; unsigned char *spos = p; *p++ = 0x02; if (BN_num_bits(s) % 8 == 0) { *p++ = BN_num_bits(s) / 8; } else { *p++ = BN_num_bits(s) / 8 + 1; BN_bn2bin(s, p); p += *spos + 1; // 填充签名数据长度 *spos += 2; *rpos += 2; *siglen = p - sig; finish: if (ec_key) { EC_KEY_free(ec_key); if (md_ctx) { EVP_MD_CTX_free(md_ctx); if (k) { BN_free(k); if (P) { EC_POINT_free(P); if (r) { BN_free(r); if (s) { BN_free(s); return ret; SM2VerifySig 函数: ```c++ #include <openssl/bn.h> #include <openssl/ec.h> #include <openssl/evp.h> #include <openssl/sm2.h> int SM2VerifySig(const unsigned char *msg, size_t msglen, const char *pubkeyfile, const unsigned char *sig, size_t siglen) int ret = 0; EC_KEY *ec_key = NULL; EVP_MD_CTX *md_ctx = NULL; unsigned char dgst[32]; size_t dgstlen; const EVP_MD *md; BIGNUM *r = NULL, *s = NULL; EC_POINT *P = NULL; // 读取 公钥 ec_key = EC_KEY_new_by_curve_name(NID_sm2); if (!ec_key) { goto finish; FILE *fp = fopen(pubkeyfile, "r"); if (!fp) { goto finish; PEM _read_EC_PUBKEY(fp, &ec_key, NULL, NULL); fclose(fp); fp = NULL; // 解析签名数据 unsigned char *p = (unsigned char *)sig; if (*p++ != 0x30) { goto finish; size_t len = *p++; if (len > siglen - 2) { goto finish; if (*p++ != 0x02) { goto finish; size_t rlen = *p++; if (rlen > len - 3) { goto finish; r = BN_new(); BN_bin2bn(p, rlen, r); p += rlen; len -= rlen + 2; if (*p++ != 0x02) { goto finish; size_t slen = *p++; if (slen != len) { goto finish; s = BN_new(); BN_bin2bn(p, slen, s); // 计算消息摘要 md = EVP_sm3(); md_ctx = EVP_MD_CTX_new(); EVP_DigestInit_ex(md_ctx, md, NULL); EVP_DigestUpdate(md_ctx, msg, msglen); EVP_DigestFinal_ex(md_ctx, dgst, &dgstlen); EVP_MD_CTX_free(md_ctx); md_ctx = NULL; // 计算椭圆曲线点 P = [s]G + [r]PA P = EC_POINT_new(EC_KEY_get0_group(ec_key)); EC_POINT *PA = EC_POINT_dup(EC_KEY_get0_public_key(ec_key), EC_KEY_get0_group(ec_key)); ret = EC_POINT_mul(EC_KEY_get0_group(ec_key), P, s, PA, r, NULL); if (ret != 1) { goto finish; // 计算 e = H(M) BIGNUM *e = BN_new(); BN_bin2bn(dgst, sizeof(dgst), e); // 计算 t = (r + x1) mod n BIGNUM *t = BN_new(); const EC_POINT *pubkey = EC_KEY_get0_public_key(ec_key); EC_POINT_get_affine_coordinates(EC_KEY_get0_group(ec_key), pubkey, t, NULL, NULL); BN_add(t, t, r); BN_mod(t, t, EC_GROUP_order(EC_KEY_get0_group(ec_key)), NULL); // 验证签名是否正确 ret = BN_cmp(t, e) == 0; finish: if (ec_key) { EC_KEY_free(ec_key); if (md_ctx) { EVP_MD_CTX_free(md_ctx); if (r) { BN_free(r); if (s) { BN_free(s); if (P) { EC_POINT_free(P); return ret; 这些函数使用 OpenSSL 库实现了 生成 非对称 密钥 对、SM2 签名和验证签名的功能。在编写程序时,需要将 OpenSSL 库链接到程序中。