- 密码哈希函数 - bcrypt
 - 密码哈希函数 - egg-bcrypt
 - 密码哈希函数 - PBKDF2
 - 密码哈希函数 - scrypt
 - crypto 模块 - 生成随机数
 - crypto 模块 - aes-256-gcm 示例1
 - crypto 模块 - aes-256-gcm 示例2
 - crypto 模块 - DH 密钥交换
 - crypto 模块 - ECDH 密钥交换
 - crypto 模块 - Hmac
 - crypto 模块 - MD5
 - crypto 模块 - RSA 的加密和解密
 - crypto 模块 - RSA 的签名和验证
 - crypto 模块 - RSA 密钥对生成
 - crypto 模块 - sha256
 - forge 模块 - 生成自签名证书
 - Forge 模块 - PKCS#5
 - forge 模块 - RSA 加密和解密
 - forge 模块 - RSA 签名和验证
 - forge 模块 - RSA 算法
 - forge 模块 - SSH 工具
 - Forge 模块 - X.509
 
本文是通过 Node.js 实现密码学中所涉及到的哈希算法、对称加密算法、非对称加密算法、密钥交换算法、数字证书生成算法等实现方式的模版代码。
涉及到的 npm 模块为:crypt、scrypt、bcrypt、forge 等。
密码哈希函数 - bcrypt
const bcrypt = require('bcrypt');// 封装 hash 函数function bcrypt_encrypt(username, password) {// 1. bcrypt 内置了生成盐值的方法:bcrypt.genSalt()// 第一个参数是循环次数(或者称因子,默认为 10)bcrypt.genSalt(10, (err, salt) => {if (err) throw err;// 2. 生成哈希值:bcrypt.hash()bcrypt.hash(password, salt, (err, key) => {if (err) throw err;// 3. 把用户名、密码哈希值和盐值存入数据库// username、key、salt});});}// 调用示例bcrypt_encrypt('zhangsan', '123456');// 对比哈希值,验证密码:bcrypt.compare(password, hash, (err, same) => {// 返回 true 或 false});
密码哈希函数 - egg-bcrypt
// config.default.jsexports.bcrypt = {saltRounds: 10 // 循环次数,默认为 10}// {app_root}/config/plugin.jsexports.bcrypt = {enable: true,package: 'egg-bcrypt'}// {app_root}/app/contoller/user.jsasync generate() {// 生成哈希值:ctx.genHash(plainText)const hash = await this.ctx.genHash(this.ctx.request.body.plainText);// Store hash in your password DB}async compare() {const { hash, plainText } = this.ctx.request.body;// 比较哈希值和原始字符串:ctx.compare(plainText, hash)const checked = await this.ctx.compare(plainText, hash);this.ctx.body = { checked };}
密码哈希函数 - PBKDF2
/** PBKDF2 是 Node.js 的 crypto 模块原生支持的标准方法。*/// 【加密示例】// PBKDF2 算法function pbkdf2_encrypt(username, password) {// 1. crypto.randomBytes()方法生成 32 字节的随机盐值crypto.randomBytes(32, (err, salt) => {if (err) throw err;// 2. 参数列表:(密码,盐值,迭代次数,输出密钥长度,摘要算法)crypto.pbkdf2(password, salt, 4096, 512, 'sha256', (err, key) => {if (err) throw err;// 3. 将用户名、密码哈希值和盐值存入数据库// Salt 盐值是明文保存的,一般不和最终生成的密钥保存在一起。console.log(username, key.toString('hex'), salt.toString('hex'));});});}// 调用示例pbkdf2_encrypt('zhangSan', '123456');// 对比哈希值,验证密码const dbsalt = 'USER RECORD SALT FROM YOUR DATABASE';const dbhash = 'USER RECORD KEY FROM YOUR DATABASE';crypto.pbkdf2(password, dbsalt, 4096, 512, 'sha256', (err, comparsehash) => {if (err) throw err;// 比较if (dbhash.toString('hex') === comparsehash.toString('hex')) {// 密码匹配} else {// 密码不匹配}});
密码哈希函数 - scrypt
const scrypt = require('scrypt');const crypto = require('crypto');function scrypt_encrypt(username, password) {// 1. 使用 crypto 的 crypto.randomBytes(...) 方法生成盐值。crypto.randomBytes(32, (err, salt) => {if (err) throw err;// 2. scrypt.hash(...) 生成 64 位的哈希值// - N: scrypt 最多使用多长时间(秒数)计算密钥(偶数)。// - r: 计算密钥时最多使用多少字节 RAM(整数)。默认为0。// - p: 计算密钥时所用 RAM 占可用值的比例(0-1,换算成百分比)默认为0.5。scrypt.hash(password, {"N":16384,"r":8,"p":1}, 64, salt, (err, key) => {if (err) throw err;// 3. 把用户名、密码哈希值和盐值存入数据库console.log(`key is ${key}`);});});}
crypto 模块 - 生成随机数
const crypto = require('crypto');// 1.异步方法生成盐值// crypto.randomBytes() 生成 16 位强加密的伪随机数crypto.randomBytes(16, (err, buf) => {if (err) throw err;console.log(`${buf.length} bytes of random data: ${buf.toString('hex')}`);console.log(`${buf.length} bytes of random data: ${buf.toString('base64')}`);});// 2.同步方法生成盐值const buf = crypto.randomBytes(256);
crypto 模块 - aes-256-gcm 示例1
/** AES-256-GCM 对称加密算法,加密、解密示例*/const crypto = require('crypto');// 初始化参数const text = 'Encryption Testing AES GCM mode'; // 要加密和解密的数据const key = crypto.randomBytes(32); // 256 位的共享密钥const iv = crypto.randomBytes(16); // 初始向量,16 字节const algorithm = 'aes-256-gcm'; // 加密算法和操作模式// 加密const cipher = crypto.createCipheriv(algorithm, key, iv); // 初始化加密算法let encrypted = cipher.update(text, 'utf8', 'hex');encrypted += cipher.final('hex');const tag = cipher.getAuthTag(); // 生成标签,用于验证密文的来源// 解密const decipher = crypto.createDecipheriv(algorithm, key, iv); // 初始化解密算法decipher.setAuthTag(tag); // 传入验证标签,验证密文的来源let decrypted = decipher.update(encrypted, 'hex', 'utf8');decrypted += decipher.final('utf8');console.log(decrypted); // Encryption Testing AES GCM mode
crypto 模块 - aes-256-gcm 示例2
const crypto = require('crypto');const aes256gcm = key => {const ALGO = 'aes-256-gcm'; // 加密算法和操作模式// encrypt returns base64-encoded ciphertextconst encrypt = str => {// Hint: the 'iv' should be unique (but not necessarily random).// 'randomBytes' here are (relatively) slow but convenient for demonstrationconst iv = new Buffer.from(crypto.randomBytes(16), 'utf8'); // 初始向量,16 字节const cipher = crypto.createCipheriv(ALGO, key, iv); // 初始化加密算法// Hint: Larger inputs (it's GCM, after all!) should use the stream APIlet enc = cipher.update(str, 'utf8', 'base64');enc += cipher.final('base64');return [ enc, iv, cipher.getAuthTag() ];};// decrypt decodes base64-encoded ciphertext into a utf8-encoded stringconst decrpt = (enc, iv, authTag) => {const decipher = crypto.createDecipheriv(ALGO, key, iv);decipher.setAuthTag(authTag);let str = decipher.update(enc, 'base64', 'utf8');str += decipher.final('utf8');return str;};return { encrypt, decrpt };};// 加密密钥// Note: a key size of 16 bytes will use AES-128, 24 => AES-192, 32 => AES-256const KEY = new Buffer.from(crypto.randomBytes(32), 'utf8');const aesCipher = aes256gcm(KEY);// 加密const [ encrypted, iv, authTag ] = aesCipher.encrypt('hello world');// 解密const decrypted = aesCipher.decrpt(encrypted, iv, authTag);console.log(decrypted); // hello world
crypto 模块 - DH 密钥交换
/*DiffieHellman 类是一个用来创建 Diffie-Hellman 键交换的工具。DiffieHellman 类的实例可以使用 crypto.createDiffieHellman() 方法。*/const crypto = require('crypto');const assert = require('assert');// Generate Alice's keys...const alice = crypto.createDiffieHellman(2048);const aliceKey = alice.generateKeys();// Generate Bob's keys...const bob = crypto.createDiffieHellman(alice.getPrime(), alice.getGenerator());const bobKey = bob.generateKeys();// Exchange and generate the secret...const aliceSecret = alice.computeSecret(bobKey);const bobSecret = bob.computeSecret(aliceKey);// OKassert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
crypto 模块 - ECDH 密钥交换
/*ECDH 类是创建椭圆曲线 Diffie-Hellman(Elliptic Curve Diffie-Hellman (ECDH))键交换的实用工具。ECDH 类的实例可以使用 crypto.createECDH() 方法。crypto.getCurves() 方法会返回一个数组,其中包含支持的椭圆曲线的名称。*/const crypto = require('crypto');const assert = require('assert');// Generate Alice's keys...const alice = crypto.createECDH('secp521r1');const aliceKey = alice.generateKeys();// Generate Bob's keys...const bob = crypto.createECDH('secp521r1');const bobKey = bob.generateKeys();// Exchange and generate the secret...const aliceSecret = alice.computeSecret(bobKey);const bobSecret = bob.computeSecret(aliceKey);assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));// OK
crypto 模块 - Hmac
const crypto = require('crypto');const key = crypto.randomBytes(16); // 密钥const hmac = crypto.createHmac('sha1', key.toString('ascii'));hmac.update('hello world');console.log(hmac.digest('hex'));// 4e1926fdb2992c927574cc9cbdc2f9d167191e89
crypto 模块 - MD5
const crypto = require('crypto');const md5 = crypto.createHash('md5');// 1. 直接对明文进行 Hashmd5.update('123456');console.log(md5.digest('hex'));// 2. 加盐 Hashlet password = '123456';let salt = 'hhug6dcKyCNBQ5sUC0i6hja5dCTqdSzV'; // 盐值// 将密码拼接上任意长度的随机字符串后,再进行 Hashmd5.update(password+salt);console.log(md5.digest('hex'));
crypto 模块 - RSA 的加密和解密
const crypto = require('crypto');const fs = require('fs');const path = require('path');const root = __dirname;const publicKey = fs.readFileSync(path.join(root, './mypubkey.pem')).toString('ascii');const privateKey = fs.readFileSync(path.join(root, './ mykey.pem')).toString('ascii');const data = 'data to crypt';// 公钥加密const encryptData = crypto.publicEncrypt(publicKey, Buffer.from(data)).toString('base64');console.log('encode', encryptData);// 私钥解密const decryptData = crypto.privateDecrypt(privateKey, Buffer.from(encryptData.toString('base64'), 'base64'));console.log('decode', decryptData.toString());
crypto 模块 - RSA 的签名和验证
const crypto = require('crypto');const fs = require('fs');const path = require('path');const root = __dirname;// 加载私钥文件const pem = fs.readFileSync(path.join(root, './rsa_private_key.pem'));const key = pem.toString('ascii');// 加载公钥文件const publicKey = fs.readFileSync(path.join(root, './rsa_public_key.pem')).toString('ascii');// 签名const sign = crypto.createSign('RSA-SHA256'); // 创建签名算法sign.update('data to sign'); // 更新待签名内容const result = sign.sign(key, 'hex'); // sign.sign() 方法用于生成并返回签名console.log('result:', result);// 验证const verify = crypto.createVerify('RSA-SHA256'); // 创建验证算法verify.update('data to sign');console.log(verify.verify(publicKey, result, 'hex')); // true
crypto 模块 - RSA 密钥对生成
/*crypto.generateKeyPair(type, options, callback)参数:* `type`:<string> 类型,要生成的算法名称,必须是 `'rsa'`、`'dsa'` 或者 `'ec'` 之一;* `options`:<Object> 类型:* `modulusLength`:<number> 类型,密钥长度(RSA,DSA);* `publicExponent`:<number> 类型,公共指数(RSA),默认值:`0x10001`;* `divisorLength`:<number> 类型,以比特为单位的 q 的大小(DSA);* `namedCurve`:<string> 类型,要使用的椭圆曲线名称(EC);* `publicKeyEncoding`:<Object> 类型,公钥编码格式:* `type`:<string> 类型,必须是 `'pkcs1'`(仅限 RSA)或 `'spki'` 之一;* `format`:<string> 类型,公钥输出格式,必须是 `'pem'` 或 `'der'` 之一;* `privateKeyEncoding`:<Object> 类型,私钥编码格式:* `type`:<string> 类型,必须是 `'pkcs1'`(仅限 RSA)或 `'pkcs8'` 或 `'sec1'`(仅限 EC) 之一;* `format`:<string> 类型,公钥输出格式,必须是 `'pem'` 或 `'der'` 之一;* `cipher`:<string> 类型,如果指定算法,将使用基于 PKCS#5 v2.0 规范的算法和密钥加密,使用给定的算法和密钥加密私钥;* `passphrase`:<string> 类型,用于加密的密钥;* `callback`:<Function> 类型:* `err`:<Error> 类型* `publicKey`:<string> 类型 | <Buffer> 类型,设置为 PEM 编码时返回 String 类型,DER 编码则返回 Buffer 类型* `privateKey`:<string> 类型 | <Buffer> 类型*/// 建议将公钥编码为 'spki' 格式,将私钥编码为 'pkcs8' 格式并加密保存:const { generateKeyPair } = require('crypto');generateKeyPair('rsa', {modulusLength: 4096,publicKeyEncoding: {type: 'spki', // pkcs1、spkiformat: 'pem'},privateKeyEncoding: {type: 'pkcs8', // pkcs1、pkcs8、sec1format: 'pem',cipher: 'aes-256-cbc',passphrase: 'top secret'}}, (err, publicKey, privateKey) => {// Handle errors and use the generated key pair.});
crypto 模块 - sha256
const crypto = require('crypto');// 创建哈希函数 sha256const hash = crypto.createHash('sha256');// 输入流编码:utf8、ascii、binary(默认)hash.update('some data to hash', 'utf8');// 输出编码:hex、binary、base64console.log(hash.digest('hex'));
forge 模块 - 生成自签名证书
const forge = require('node-forge');// 生成 RSA 密钥对,以创建自签名证书,并保存到 MongoDB 数据库const cert = forge.pki.createCertificate();const keys = forge.pki.rsa.generateKeyPair(2048);cert.publicKey = keys.publicKey;cert.serialNumber = '01';// 证书有效期cert.validity.notBefore = new Date();cert.validity.notAfter = new Date();cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);const attrs = [{name: 'commonName',value: payload.username, // 默认名称为用户名},{name: 'countryName',value: 'china',},{shortName: 'ST',value: 'Virginia',},{name: 'localityName',value: 'Blacksbury',},{name: 'organizationName',value: 'tonintech',},{shortName: 'OU',value: 'test',},];cert.setSubject(attrs);cert.setIssuer(attrs);// 证书扩展cert.setExtensions([{name: 'basicConstraints',cA: true,pathLenConstraint: 4,},{name: 'keyUsage',keyCertSign: true,digitalSignature: true,nonRepudiation: true,keyEncipherment: true,dataEncipherment: true,},{name: 'extKeyUsage',serverAuth: true,clientAuth: true,codeSigning: true,emailProtection: true,timeStamping: true,},{name: 'nsCertType',client: true,server: true,email: true,objsign: true,sslCA: true,emailCA: true,objCA: true,},{name: 'subjectAltName',altNames: [{type: 6, // URIvalue: 'http://example.org/webid#me',},{type: 7, // IPip: '127.0.0.1',},],},{name: 'subjectKeyIdentifier',},]);// TODO: add authorityKeyIdentifier extension// 自签名证书cert.sign(keys.privateKey, forge.md.sha256.create());this.logger.debug('证书创建成功');// PEM-format keys and certconst pem = {privateKey: forge.pki.privateKeyToPem(keys.privateKey),publicKey: forge.pki.publicKeyToPem(keys.publicKey),certificate: forge.pki.certificateToPem(cert),};// 保存到 mongoDB 数据库:数字证书const CertificateEntity = new ctx.model.Certificates({certificate: pem.certificate,privateKey: pem.privateKey,});const certificate = await CertificateEntity.save();
Forge 模块 - PKCS#5
/*实现基于 PKCS#5 的基于口令的密钥派生功能。PBKDF2 !!!*/// 生成基于口令的 16 进制密钥// note an optional message digest can be passed as the final parameter// 注意,可以将可选的消息摘要算法作为最终参数传递var salt = forge.random.getBytesSync(128);var derivedKey = forge.pkcs5.pbkdf2('password', salt, numIterations, 16);// 异步生成密钥// note an optional message digest can be passed before the callbackforge.pkcs5.pbkdf2('password', salt, numIterations, 16, function(err, derivedKey) {// do something w/derivedKey});
forge 模块 - RSA 加密和解密
const forge = require('node-forge');// 同步方式生成 RSA-2048 密钥对const keyPair = forge.pki.rsa.generateKeyPair(2048);const privateKey = keyPair.privateKey;const publicKey = keyPair.publicKey;// 加密和解密,默认 RSAES PKCS#1 v1.5const encrypted = publicKey.encrypt(bytes);const decrypted = privateKey.decrypt(encrypted);// 加密和解密,使用 RSAES PKCS#1 v1.5const encrypted = publicKey.encrypt(bytes, 'RSAES-PKCS1-V1_5');const decrypted = privateKey.decrypt(encrypted, 'RSAES-PKCS1-V1_5');// 加密和解密,使用 RSAES-OAEPconst encrypted = publicKey.encrypt(bytes, 'RSA-OAEP');const decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP');// 加密和解密,使用 RSAES-OAEP/SHA-256const encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', {md: forge.md.sha256.create(),});const decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', {md: forge.md.sha256.create(),});// 加密和解密,使用 RSAES-OAEP/SHA-256/MGF1-SHA-1// 兼容 Java 的 RSA/ECB/OAEPWithSHA-256AndMGF1Paddingvar encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', {md: forge.md.sha256.create(),mgf1: {md: forge.md.sha1.create(),},});var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', {md: forge.md.sha256.create(),mgf1: {md: forge.md.sha1.create(),},});
forge 模块 - RSA 签名和验证
const forge = require('node-forge');// 同步方式生成 RSA-2048 密钥对const keyPair = forge.pki.rsa.generateKeyPair(2048);const privateKey = keyPair.privateKey;const publicKey = keyPair.publicKey;// ------------------- RSASSA PKCS#1 v1.5 模式 --------------------------------// 使用私钥对数据进行签名并输出 DER 编码的字节// 默认为 RSASSA PKCS#1 v1.5 模式const md = forge.md.sha1.create();md.update('sign this', 'utf8');const signature = privateKey.sign(md);// 使用公钥验证数据const verified = publicKey.verify(md.digest().bytes(), signature);console.log(verified); // true// ------------------- RSASSA-PSS 模式 --------------------------------// 签名和验证,使用 RSASSA-PSS 模式// 其中,PSS 使用 SHA-1 作为哈希算法,SHA-1 基于 MGF1 函数,盐值长度为 20 bytevar md = forge.md.sha1.create();md.update('sign this', 'utf8');var pss = forge.pss.create({md: forge.md.sha1.create(),mgf: forge.mgf.mgf1.create(forge.md.sha1.create()),saltLength: 20,// optionally pass 'prng' with a custom PRNG implementation// optionalls pass 'salt' with a forge.util.ByteBuffer w/custom salt});var signature = privateKey.sign(md, pss);// 验证 RSASSA-PSS 签名var pss = forge.pss.create({md: forge.md.sha1.create(),mgf: forge.mgf.mgf1.create(forge.md.sha1.create()),saltLength: 20,// optionally pass 'prng' with a custom PRNG implementation});var md = forge.md.sha1.create();md.update('sign this', 'utf8');publicKey.verify(md.digest().getBytes(), signature, pss);
forge 模块 - RSA 算法
const forge = require('node-forge');// 同步方式生成 RSA-2048 密钥对(不推荐)const keyPair = forge.pki.rsa.generateKeyPair(2048);// 异步方式生成 RSA-2048 密钥对rsa.generateKeyPair({bits: 2048, workers: 2}, function(err, keypair) {// keypair.privateKey, keypair.publicKey});// 转换为 PEM 格式const privateKey = forge.pki.privateKeyToPem(keyPair.privateKey);const publicKey = forge.pki.publicKeyToPem(keyPair.publicKey);// 保存到数据库const KeyPairEntity = new ctx.model.KeyPairs({publicKey: publicKey,privateKey: privateKey,});const result = await KeyPairEntity.save();
forge 模块 - SSH 工具
// 将一个 RSA 私钥文件编码(可选加密)为 Putty PPK 文件forge.ssh.privateKeyToPutty(privateKey, passphrase, comment);// 将一个 RSA 公钥文件编码为 OpenSSH 文件forge.ssh.publicKeyToOpenSSH(key, comment);// 将一个 RSA 私钥文件编码为 OpenSSH 文件forge.ssh.privateKeyToOpenSSH(privateKey, passphrase);// 从字节缓冲区(byte buffer)中获取 SSH 公钥指纹forge.ssh.getPublicKeyFingerprint(key);// 获取十六进制编码,以冒号分隔的 SSH 公钥指纹forge.ssh.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'});
Forge 模块 - X.509
var pki = forge.pki;// 将 PEM 格式的公钥转换为 Forge 公钥var publicKey = pki.publicKeyFromPem(pem);// 将 Forge 公钥转换为 PEM 格式的公钥var pem = pki.publicKeyToPem(publicKey);// convert an ASN.1 SubjectPublicKeyInfo to a Forge public keyvar publicKey = pki.publicKeyFromAsn1(subjectPublicKeyInfo);// convert a Forge public key to an ASN.1 SubjectPublicKeyInfovar subjectPublicKeyInfo = pki.publicKeyToAsn1(publicKey);// gets a SHA-1 RSAPublicKey fingerprint a byte buffer// 获取 RSA 公钥的 SHA-1 指纹,Byte buffer 格式pki.getPublicKeyFingerprint(key);// gets a SHA-1 SubjectPublicKeyInfo fingerprint a byte bufferpki.getPublicKeyFingerprint(key, {type: 'SubjectPublicKeyInfo'});// gets a hex-encoded, colon-delimited SHA-1 RSAPublicKey public key fingerprint// 获取以十六进制编码,冒号分隔的 SHA-1 RSAPublicKey 公钥指纹pki.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'});// gets a hex-encoded, colon-delimited SHA-1 SubjectPublicKeyInfo public key fingerprintpki.getPublicKeyFingerprint(key, {type: 'SubjectPublicKeyInfo',encoding: 'hex',delimiter: ':'});// gets a hex-encoded, colon-delimited MD5 RSAPublicKey public key fingerprint// 获取十六进制编码,冒号分隔的 MD5 RSAPublicKey 公钥指纹pki.getPublicKeyFingerprint(key, {md: forge.md.md5.create(),encoding: 'hex',delimiter: ':'});// creates a CA store// 创建一个 CA 仓库var caStore = pki.createCaStore([/* PEM-encoded cert */, ...]);// add a certificate to the CA store// 添加一张证书到 CA 仓库caStore.addCertificate(certObjectOrPemString);// gets the issuer (its certificate) for the given certificate// 获取给定证书的颁发者(其证书)var issuerCert = caStore.getIssuer(subjectCert);// verifies a certificate chain against a CA store// 根据 CA 仓库验证证书链pki.verifyCertificateChain(caStore, chain, customVerifyCallback);// signs a certificate using the given private key// 使用给定的私钥为证书签名cert.sign(privateKey);// signs a certificate using SHA-256 instead of SHA-1// 使用 SHA-256 而不是 SHA-1 为证书签名cert.sign(privateKey, forge.md.sha256.create());// verifies an issued certificate using the certificates public key// 使用证书公钥验证已颁发的证书var verified = issuer.verify(issued);// generate a keypair and create an X.509v3 certificate// 生成密钥对并创建 X.509v3 证书var keys = pki.rsa.generateKeyPair(2048);var cert = pki.createCertificate();cert.publicKey = keys.publicKey;// alternatively set public key from a csr// 或者通过 csr 设置公钥//cert.publicKey = csr.publicKey;// NOTE: serialNumber is the hex encoded value of an ASN.1 INTEGER.// 注意:serialNumber 是 ASN.1 INTEGER 的十六进制编码值。// Conforming CAs should ensure serialNumber is:// 符合要求的 CA 应确保 serialNumber 为:// - no more than 20 octets// - 不超过20个八位位组// - non-negative (prefix a '00' if your value starts with a '1' bit)// - 非负数(如果您的值以“ 1”开头,则前缀为“ 00”)cert.serialNumber = '01';cert.validity.notBefore = new Date();cert.validity.notAfter = new Date();cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);var attrs = [{name: 'commonName',value: 'example.org'}, {name: 'countryName',value: 'US'}, {shortName: 'ST',value: 'Virginia'}, {name: 'localityName',value: 'Blacksburg'}, {name: 'organizationName',value: 'Test'}, {shortName: 'OU',value: 'Test'}];cert.setSubject(attrs);// alternatively set subject from a csr// 或者通过 csr 设置主题//cert.setSubject(csr.subject.attributes);cert.setIssuer(attrs);// 证书扩展项cert.setExtensions([{name: 'basicConstraints',cA: true}, {name: 'keyUsage',keyCertSign: true,digitalSignature: true,nonRepudiation: true,keyEncipherment: true,dataEncipherment: true}, {name: 'extKeyUsage',serverAuth: true,clientAuth: true,codeSigning: true,emailProtection: true,timeStamping: true}, {name: 'nsCertType',client: true,server: true,email: true,objsign: true,sslCA: true,emailCA: true,objCA: true}, {name: 'subjectAltName',altNames: [{type: 6, // URIvalue: 'http://example.org/webid#me'}, {type: 7, // IPip: '127.0.0.1'}]}, {name: 'subjectKeyIdentifier'}]);/* alternatively set extensions from a csr或者通过 CSR 设置扩展项var extensions = csr.getAttribute({name: 'extensionRequest'}).extensions;// optionally add more extensionsextensions.push.apply(extensions, [{name: 'basicConstraints',cA: true}, {name: 'keyUsage',keyCertSign: true,digitalSignature: true,nonRepudiation: true,keyEncipherment: true,dataEncipherment: true}]);cert.setExtensions(extensions);*/// self-sign certificate// 自签名证书cert.sign(keys.privateKey);// convert a Forge certificate to PEM// 将 Forge 证书转换为 PEM 格式var pem = pki.certificateToPem(cert);// convert a Forge certificate from PEM// 将 PEM 格式证书转换为 Forgevar cert = pki.certificateFromPem(pem);// convert an ASN.1 X.509x3 object to a Forge certificatevar cert = pki.certificateFromAsn1(obj);// convert a Forge certificate to an ASN.1 X.509v3 objectvar asn1Cert = pki.certificateToAsn1(cert);
