# RSA crypto-js-wasm当前已经支持RSA! RSA算法的各种常规用法当前已经支持, 包括`生成密钥`, `加密`, `解密`, `签名`和`验签`. ### 配置说明 RSA的配置项应为一个object, 可以包含如下属性: - encryptPadding - 类型: `string` - 默认值: `OAEP` - 有效值: `OAEP`/`PKCS1V15` 用于`encrypt`和`decrypt`的填充模式, 大小写不敏感. - signPadding - 类型: `string` - 默认值:: `PSS` - 有效值: `PSS`/`PKCS1V15` 用于`sign`和`verify`的填充模式, 大小写不敏感. - hashAlgo - 类型: `string` - 默认值:: `SHA256` - 有效值: `MD5`/`SHA1`/`SHA224`/`SHA256`/`SHA384`/`SHA512`/`RIPEMD160` 用于`encrypt`, `decrypt`, `sign`和`verify`的哈希算法, 大小写不敏感. - key - 类型: `string` | `number` - 默认值:: `1024` 当 `key`是`string`类型时: 可以是RSA key文件的路径, 也可以是RSA key的内容. - RSA key的内容: 应当以 `-----BEGIN PRIVATE KEY-----`或`-----BEGIN PUBLIC KEY-----`开始. 同时在`browser`和`nodejs`环境下可用. - RSA key文件的路径: 不以`-----BEGIN PRIVATE KEY-----`或`-----BEGIN PUBLIC KEY-----`开始的字符串,将被视作key文件的路径. 只在`nodejs`环境下可用. 当 `key`是`number`类型时: RSA key的位长. 我们会根据这个位长重新生成一对RSA公钥和私钥. - isPublicKey - 类型: `boolean` - 默认值:: `false` 若配置的`key`是公钥, 则应设置为true. 需要与`key`同时进行配置。 需要注意的是, RSA私钥可以生成公钥, 因此当配置了RSA私钥时, 对应的RSA公钥也会生成. 但是RSA公钥**不能**生成私钥. RSA私钥在 `decrypt`和`sign`调用时需要用到, 因此, 如果没有配置RSA私钥, 在调用`decrypt`, `sign`, `generateKeyFile`(生成`pairs`/`private`时) and `getKeyContent`(获取私钥时)时会报错. 配置项可以通过如下方式进行配置: ```javascript import C from '@originjs/crypto-js-wasm'; // 等待异步的读取wasm完成 await C.RSA.loadWasm(); const config = { encryptPadding: 'OAEP', signPadding: 'PSS', hashAlgo: 'md5', key: '/home/user/rsa_private_key.pem', isPublicKey: false } // 可以通过updateConfig方法更新配置 C.RSA.updateConfig(config); // 也可以在调用encrypt/decrypt/digest/sign/verify等api时进行配置更新 const encryptedMessage = C.RSA.encrypt('message', { encryptPadding: 'PKCS1V15' key: '/home/user/rsa_private_key.pem', }); const digest = C.RSA.digest('message', { hashAlgo: 'sha256' }); const signature = C.RSA.sign('message', { signPadding: 'pkcs1v15' }); ``` ### 创建RSA实例 ```javascript import C from '@originjs/crypto-js-wasm'; // 与crypto-js-wasm中的其他算法一样, 你可以自己创建一个RSA示例 const rsa = new C.algo.RSA(); rsa.loadWasm(); let keyContent = rsa.getKeyContent('private', 'pem'); let encrypted = rsa.encrypt('mesage'); // 你也可以使用我们准备好的RSA示例 keyContent = C.RSA.getKeyContent('private', 'pem'); encrypted = C.RSA.encrypt('mesage'); ``` ### 更新RSA密钥 默认情况下, 我们会生成一对1024位长的公钥和私钥. 你可以通过`updateConfig`或`updateRsaKey`方法更新密钥. ```javascript import C from '@originjs/crypto-js-wasm'; await C.RSA.loadWasm(); // 你可以获取默认的RSA密钥 const privateKeyContent = C.RSA.getKeyContent('private', 'pem'); const publicKeyContent = C.RSA.getKeyContent('public', 'pem'); // 你也可以重新生成一份RSA密钥 C.RSA.updateRsaKey(2048); // 同时也可以指定一个已存在的RSA密钥 C.RSA.updateConfig({ key: '/home/rsa_private_key.pem' }); // 你可以生成RSA密钥文件 // 私钥文件会生成在./keys/key.dem C.RSA.generateKeyFile('private'); // 公钥 : /home/lee/my_rsa_keys/my_rsa_keys_public.pem // 私钥 : /home/lee/my_rsa_keys/my_rsa_keys_private.pem C.RSA.generateKeyFile('pairs', 'pem', 'my_rsa_keys', '/home/lee/my_rsa_keys'); ``` ### 加密和解密 ```javascript import C from '@originjs/crypto-js-wasm'; await C.RSA.loadWasm(); const msg = 'testMessage'; const encrypted = C.RSA.encrypt(msg, {encryptPadding: 'pkcs1v15',}); const decrypted = C.RSA.decrypt(encrypted, {encryptPadding: 'pkcs1v15',}); expect(new TextDecoder().decode(decrypted)).toBe(msg); ``` ### 摘要, 签名和验签 你可以用`md5`, `sha1`或其他hash算法自行生成摘要, 但是我们建议你使用`RSA.digest`方法生成密钥, 这是因为你生成密钥所用的hash算法必须与`sign`和`verify`时的一致. 通过使用`RSA.digest`, 我们可以保证`digest`, `sign`和`verify`中hash算法的一致性. You can get the digest using hash algorithms like `md5`, `sha1` or other ones by yourself. But it's recommended to use `RSA.digest`, because the hasher you used in `digest` must be the same with the ones in `sign` and `verify`. By using `RSA.digest`, we can assure the consistency of the hasher in `digest`, `sign` and `verify`. ```javascript import C from '@originjs/crypto-js-wasm'; await C.RSA.loadWasm(); const message = 'test message'; const digest = C.RSA.digest(message, {hashAlgo: 'md5',}); const signature = C.RSA.sign(digest, {signPadding: 'pkcs1v15',}); expect(C.RSA.verify(digest, signature)).toBe(true); const errorDigest = C.RSA.digest('another message', {hashAlgo: 'md5',}); expect(C.RSA.verify(errorDigest, signature)).toBe(false); ``` ### 注意 `initFromKeyFile` 和 `generateKeyFile` 的内部实现依赖于 `nodejs` 的 `fs`(因为他们就是设计用来从文件中读取,或写入文件的),这意味着他们不能在浏览器中使用。如果在非`nodejs`环境使用他们,我们会报错,但是方法内部所使用的`fs`在`webpack`中还是可能报错: ```shell Module not found: Error: Can't resolve 'fs' in '...\node_modules\@originjs\crypto-js-wasm\lib' ``` 对于 `webpack > 5`, 你可以在 `webpack.config.js` 中添加如下配置来避免此报错(通过[这个issue](https://github.com/webpack-contrib/css-loader/issues/447)可以查看更多细节): ```javascript module.exports = { ... resolve: { fallback: { fs: false }, } } ```