npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

browser-rsa

v1.0.6

Published

pure js rsa, rsa for browser, 微信小程序 rsa

Downloads

4

Readme

纯 js 实现 rsa,无第三方依赖,适用于某些环境无 crypto 场景。比如:微信小程序。

支持: 私钥加密 -> 公钥解密 公钥加密 -> 私钥解密

生成密钥

生成私钥

➜  openssl genrsa -out key1.pem 512
➜  cat key1.pem
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAKBKx4EJPI9rjYV1nfyPjdOZoeyHVxbYwrRLkxyNRoRGYRPmaShJ
Zd0dGlMw1Cm70BCpzz0iswMyJIj88yoVg18CAwEAAQJAPUwbewbzN81jc1QFNJ4Z
GIA54d/nt/7whk4YVeTYwKAmYJ7nXV1G9rioQ2CUb0MuBOVBgZaPdKNT+3bkbrEb
kQIhANEpPGOruTbTSbWIlTNxRxZvsPT/kUKeraNpBT6k2rBrAiEAxC/8/DBAysAz
yilUg+V3OY54czTtA1la7KLpI91TZd0CIQC16K0y6lkNS7mhfoZ01SJEayN2EQee
7y6JHn+HOg1QvQIhAJz0Q3JC7GMIt6ZBwIKw/txGNej9a6zlPM/aWai+tazlAiA0
w9ttPRc/TukSp8fHZBzWdszSU5SO/IwTKVmeLmnC0g==
-----END RSA PRIVATE KEY-----

从私钥生成公钥

➜  openssl rsa -in key1.pem -pubout -out pubkey.pem
➜  cat pubkey.pem
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKBKx4EJPI9rjYV1nfyPjdOZoeyHVxbY
wrRLkxyNRoRGYRPmaShJZd0dGlMw1Cm70BCpzz0iswMyJIj88yoVg18CAwEAAQ==
-----END PUBLIC KEY-----

安装

npm install browser-rsa

使用

RSA

import BrowserRsa from 'browser-rsa'
import utils from 'browser-rsa/lib/utils.js'
const pubkey = `MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKBKx4EJPI9rjYV1nfyPjdOZoeyHVxbY
wrRLkxyNRoRGYRPmaShJZd0dGlMw1Cm70BCpzz0iswMyJIj88yoVg18CAwEAAQ==`
const privateKey = `MIIBOwIBAAJBAKBKx4EJPI9rjYV1nfyPjdOZoeyHVxbYwrRLkxyNRoRGYRPmaShJ
Zd0dGlMw1Cm70BCpzz0iswMyJIj88yoVg18CAwEAAQJAPUwbewbzN81jc1QFNJ4Z
GIA54d/nt/7whk4YVeTYwKAmYJ7nXV1G9rioQ2CUb0MuBOVBgZaPdKNT+3bkbrEb
kQIhANEpPGOruTbTSbWIlTNxRxZvsPT/kUKeraNpBT6k2rBrAiEAxC/8/DBAysAz
yilUg+V3OY54czTtA1la7KLpI91TZd0CIQC16K0y6lkNS7mhfoZ01SJEayN2EQee
7y6JHn+HOg1QvQIhAJz0Q3JC7GMIt6ZBwIKw/txGNej9a6zlPM/aWai+tazlAiA0
w9ttPRc/TukSp8fHZBzWdszSU5SO/IwTKVmeLmnC0g==`

const rsa = new BrowserRsa()
// 设置 key,二选一
rsa.setPublicKey(pubkey)
rsa.setPrivateKey(privateKey)

const str = 'hello world'
const pStr = rsa.publicEncrypt(str)
const pdStr = rsa.privateDecrypt(pStr)
console.log(str == pdStr, pStr)

AES-CTR,对称加密的工具类

import BrowserAesCtr from 'browser-rsa/BrowserAesCtr.js'
import utils from 'browser-rsa/lib/utils.js';
const text = "测试文本🧰"

const counter = new Uint8Array([191, 167, 0, 170, 152, 141, 171, 32, 5, 69, 177, 137, 21, 204, 229, 225]);  // set random initialisation vector

const key = new Uint8Array([87, 219, 91, 67, 114, 196, 219, 8, 184, 193, 91, 186, 139, 33, 7, 212])
// 内部 counter 会自增
let aesCtr = new BrowserAesCtr(key, counter)
const encrypt = aesCtr.encrypt(text)

aesCtr = new BrowserAesCtr(key, counter)
const decrypt = aesCtr.decrypt(encrypt)
console.log(text == utils.utf8.fromByteArray(decrypt))

API 说明

RSA

class BrowserRsa {
    /**
     * @param {String} padding rsa padding, support RSA_PKCS1_PADDING and RSA_PKCS1_OAEP_PADDING, default is RSA_PKCS1_OAEP_PADDING
     * padding set only for : private key decrypt, public key encrypt
     * private key encrypt, public key decrypt is use RSA_PKCS1_PADDING
     */
    constructor(padding)
  
    setPublicKey(base64str)
    /**
     * https://crypto.stackexchange.com/questions/21102/what-is-the-ssl-private-key-file-format
     * @param {String} base64str 
     */
    setPrivateKey(base64str) 
    /**
     * @param {String} str 
     * @param {String} resultEncoding return encoding, array, base64 or hex, default base64
     * @returns {String|Array}
     */
    publicEncrypt(str, resultEncoding = 'base64')
    /**
     * 
     * @param {String} ctext hex or base64
     * @param {String} encoding ctext encoding, array, base64 or hex, default base64
     * @param {String} resultEncoding return encoding, array or utf8 default utf8
     * @returns {String|Array}
     */
    publicDecrypt(ctext, encoding = 'base64', resultEncoding)
    /**
     * @param {String} str 
     * @param {String} resultEncoding return encoding, array, base64 or hex, default base64
     * @returns {String|Array}
     */
    privateEncrypt(str, resultEncoding = 'base64')
    /**
     * 
     * @param {String} ctext hex or base64
     * @param {Boolean} encoding ctext encoding, array, base64 or hex, default base64
     * @param {Boolean} resultEncoding return encoding, array or utf8 default utf8
     * @returns {String|Array}
     */
    privateDecrypt(str, encoding = 'base64', resultEncoding) 
}

AES

class BrowserAesCtr {
    /**
     * 
     * @param {Uint8Array|Array} key 
     * @param {Uint8Array|Array} counter 
     */
    constructor(key, counter)
    /**
     * 
     * @param {Array|String} data 
     * @returns {Uint8Array}
     */
    encrypt(data)
    /**
     * 
     * @param {Array|String} data if string, must be base64
     * @returns {Uint8Array}
     */
    decrypt(data)
}

utils 工具类

import utils from "browser-rsa/lib/utils";

// base64 处理
utils.base64.encode // 支持 utf8 字符集。(TextEncoder + btoa)
utils.base64.decode // 支持 utf8 字符集。(TextDecoder + atob)
utils.base64.fromHex
utils.base64.toHex
utils.base64.toByteArray
utils.base64.fromByteArray
utils.base64.fromBase64Url
utils.base64.toBase64Url

utils.hex.toByteArray
utils.hex.fromByteArray

// 同 TextEncoder.encode
utils.utf8.toByteArray
// 同 TextDecoder.decode
utils.utf8.fromByteArray

// 生成随机数
utils.random.nextByte()
utils.random.nextBytes(arr)

原理

RSA 算法基于:http://www-cs-students.stanford.edu/~tjw/jsbn/

简单说下密钥解析。

  • 私钥格式
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 
}

(n、d):私钥,这个我们要私密保存。
(n、e):公钥,可以对外公布。
n:模数(Modulus),私钥和公钥都包含有这个数。
e:公钥指数(publicExponent),一般是固定值65537。
d:私钥指数(privateExponent)。

密钥是使用 ASN.1 编码 ,然后再 base64。

用如下命令,可以解析出上面的格式。

➜  openssl rsa -in key1.pem -text -noout
RSA Private-Key: (512 bit)
modulus:
    00:cf:14:0d:20:e3:fc:79:2f:42:b1:e2:0e:ea:26:
    fb:e4:4a:1e:ab:7e:3c:56:41:a9:ae:fa:43:b2:17:
    16:7c:55:c9:38:03:0f:9b:7d:68:c9:e2:7a:55:be:
    95:80:f9:41:f9:13:62:48:fe:f3:d4:44:00:a2:32:
    a7:ac:5b:2d:fd
publicExponent: 65537 (0x10001)
privateExponent:
    02:ba:11:de:30:02:60:1a:26:37:af:71:60:d5:f8:
    95:2e:00:af:63:6f:29:f7:9d:63:67:7a:42:bb:19:
    19:b4:05:6c:4a:b2:32:c7:cb:62:41:ed:fe:b0:79:
    37:61:15:1d:1d:84:f9:e5:ca:96:6a:d0:e3:13:10:
    35:57:ef:a1
prime1:
    00:ed:1b:8a:fb:c5:a2:fe:b2:5e:53:84:dc:fc:f3:
    4a:2b:5e:f7:ac:6e:fc:6a:aa:e6:f5:52:fa:38:7e:
    0d:54:19
prime2:
    00:df:93:fa:c0:0a:a8:3b:cc:f7:78:35:4d:99:c8:
    a0:68:1e:84:b1:93:2e:97:56:a1:2e:58:6e:56:bc:
    5a:05:85
exponent1:
    20:91:89:f3:af:60:06:30:25:f8:be:e5:43:f1:7f:
    1c:99:fc:d7:38:9f:7f:5f:5e:3e:10:59:c2:6c:be:
    13:f1
exponent2:
    31:19:f5:b2:e1:64:4b:25:db:9f:89:cd:4e:1d:d2:
    a4:ab:37:27:2c:94:c9:e5:db:a6:2b:03:a8:86:db:
    1a:65
coefficient:
    20:22:85:e8:ca:e1:ce:fa:b8:c8:fc:ed:05:4e:16:
    a9:8f:51:c6:c0:60:50:15:72:56:b2:e6:88:3e:20:
    4f:05

解析过程只需要用 js 实现,然后再加上 jsbn 就组成了 RSA 加密、解密。