Compare commits
	
		
			No commits in common. "master" and "v0.8.2" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										11
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								.drone.yml
									
									
									
									
									
								
							@ -1,11 +0,0 @@
 | 
				
			|||||||
kind: pipeline
 | 
					 | 
				
			||||||
name: default
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pipeline:
 | 
					 | 
				
			||||||
  build:
 | 
					 | 
				
			||||||
    image: node
 | 
					 | 
				
			||||||
    environment:
 | 
					 | 
				
			||||||
      RASHA_TEST_LARGE_KEYS: "true"
 | 
					 | 
				
			||||||
    commands:
 | 
					 | 
				
			||||||
      - npm install --ignore-scripts
 | 
					 | 
				
			||||||
      - npm test
 | 
					 | 
				
			||||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,2 +0,0 @@
 | 
				
			|||||||
all.*
 | 
					 | 
				
			||||||
.*.sw*
 | 
					 | 
				
			||||||
							
								
								
									
										89
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										89
									
								
								README.md
									
									
									
									
									
								
							@ -1,59 +1,25 @@
 | 
				
			|||||||
[Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js)
 | 
					Rasha.js
 | 
				
			||||||
=========
 | 
					=========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
A [Root](https://therootcompany.com) Project.
 | 
					Sponsored by [Root](https://therootcompany.com).
 | 
				
			||||||
Built for [ACME.js](https://git.coolaj86.com/coolaj86/acme.js)
 | 
					Built for [ACME.js](https://git.coolaj86.com/coolaj86/acme.js)
 | 
				
			||||||
and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js)
 | 
					and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| ~550 lines of code | 3kb gzipped | 10kb minified | 18kb with comments |
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RSA tools. Lightweight. Zero Dependencies. Universal compatibility.
 | 
					RSA tools. Lightweight. Zero Dependencies. Universal compatibility.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* [x] Fast and Easy RSA Key Generation
 | 
					 | 
				
			||||||
* [x] PEM-to-JWK
 | 
					* [x] PEM-to-JWK
 | 
				
			||||||
* [x] JWK-to-PEM
 | 
					* [ ] JWK-to-PEM (in progress)
 | 
				
			||||||
* [x] JWK thumbprint
 | 
					 | 
				
			||||||
* [x] SSH "pub" format
 | 
					* [x] SSH "pub" format
 | 
				
			||||||
* [ ] ECDSA
 | 
					 | 
				
			||||||
  * **Need EC or ECDSA tools?** Check out [Eckles.js](https://git.coolaj86.com/coolaj86/eckles.js)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!-- This project is fully functional and tested (and the code is pretty clean).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Generate RSA Key
 | 
					It is considered to be complete, but if you find a bug please open an issue. -->
 | 
				
			||||||
 | 
					 | 
				
			||||||
Achieves the *fastest possible key generation* using node's native RSA bindings to OpenSSL,
 | 
					 | 
				
			||||||
then converts to JWK for ease-of-use.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
Rasha.generate({ format: 'jwk' }).then(function (keypair) {
 | 
					 | 
				
			||||||
  console.log(keypair.private);
 | 
					 | 
				
			||||||
  console.log(keypair.public);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**options**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* `format` defaults to `'jwk'`
 | 
					 | 
				
			||||||
  * `'pkcs1'` (traditional)
 | 
					 | 
				
			||||||
  * `'pkcs8'` <!-- * `'ssh'` -->
 | 
					 | 
				
			||||||
* `modulusLength` defaults to 2048 (must not be lower)
 | 
					 | 
				
			||||||
  * generally you shouldn't pick a larger key size - they're slow
 | 
					 | 
				
			||||||
  * **2048** is more than sufficient
 | 
					 | 
				
			||||||
  * 3072 is way, way overkill and takes a few seconds to generate
 | 
					 | 
				
			||||||
  * 4096 can take about a minute to generate and is just plain wasteful
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**advanced options**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
These options are provided for debugging and should not be used.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* `publicExponent` defaults to 65537 (`0x10001`)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## PEM-to-JWK
 | 
					## PEM-to-JWK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* [x] PKCS#1 (traditional)
 | 
					* [x] PKCS#1 (traditional)
 | 
				
			||||||
* [x] PKCS#8, SPKI/PKIX
 | 
					* [x] PKCS#8, SPKI/PKIX
 | 
				
			||||||
* [x] 2048-bit, 3072-bit, 4096-bit (and ostensibily all others)
 | 
					* [x] 2048-bit, 4096-bit (and ostensibily all others)
 | 
				
			||||||
* [x] SSH (RFC4716), (RFC 4716/SSH2)
 | 
					* [x] SSH (RFC4716), (RFC 4716/SSH2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```js
 | 
					```js
 | 
				
			||||||
@ -83,7 +49,7 @@ Rasha.import({ pem: pem }).then(function (jwk) {
 | 
				
			|||||||
## JWK-to-PEM
 | 
					## JWK-to-PEM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* [x] PKCS#1 (traditional)
 | 
					* [x] PKCS#1 (traditional)
 | 
				
			||||||
* [x] PKCS#8, SPKI/PKIX
 | 
					* [ ] PKCS#8, SPKI/PKIX
 | 
				
			||||||
* [x] 2048-bit, 4096-bit (and ostensibily all others)
 | 
					* [x] 2048-bit, 4096-bit (and ostensibily all others)
 | 
				
			||||||
* [x] SSH (RFC4716), (RFC 4716/SSH2)
 | 
					* [x] SSH (RFC4716), (RFC 4716/SSH2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -101,14 +67,18 @@ Rasha.export({ jwk: jwk }).then(function (pem) {
 | 
				
			|||||||
-----BEGIN RSA PRIVATE KEY-----
 | 
					-----BEGIN RSA PRIVATE KEY-----
 | 
				
			||||||
MIIEpAIBAAKCAQEAm2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhD
 | 
					MIIEpAIBAAKCAQEAm2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhD
 | 
				
			||||||
NzUJefLukC+xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLICOFcCGMob6pSQ
 | 
					NzUJefLukC+xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLICOFcCGMob6pSQ
 | 
				
			||||||
38P8LdAIlb0pqDHxEJ9adWomjuFf.....5cCBahfsiNtNR6WV1/iCSuINYs6uPdA
 | 
					38P8LdAIlb0pqDHxEJ9adWomjuFf0...e5cCBahfsiNtNR6WV1/iCSuINYs6uPdA
 | 
				
			||||||
Jlw7hm9m8TAmFWWyfL0s7wiRvAYkQvpxetorTwHJVLabBDJ+WBOAY2enOLHIRQv+
 | 
					Jlw7hm9m8TAmFWWyfL0s7wiRvAYkQvpxetorTwHJVLabBDJ+WBOAY2enOLHIRQv+
 | 
				
			||||||
atAvHrLXjkUdzF96o0icyF6n7QzGfUPmeWGYg6BEClLS31Whe0eEVQ==
 | 
					atAvHrLXjkUdzF96o0icyF6n7QzGfUPmeWGYg6BEClLS31Whe0eEVQ==
 | 
				
			||||||
-----END RSA PRIVATE KEY-----
 | 
					-----END RSA PRIVATE KEY-----
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Advanced Options
 | 
					### Advanced Options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!--
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`format: 'pkcs8'`:
 | 
					`format: 'pkcs8'`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The default output format `pkcs1` (RSA-specific format) is used for private keys.
 | 
					The default output format `pkcs1` (RSA-specific format) is used for private keys.
 | 
				
			||||||
@ -125,7 +95,7 @@ Rasha.export({ jwk: jwk, format: 'pkcs8' }).then(function (pem) {
 | 
				
			|||||||
-----BEGIN PRIVATE KEY-----
 | 
					-----BEGIN PRIVATE KEY-----
 | 
				
			||||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCba21UHE+VbDTp
 | 
					MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCba21UHE+VbDTp
 | 
				
			||||||
mYYFZUOV+OQ8AngOCdjROsPC0KiEfMvEaEM3NQl58u6QL7G7QsErKViiNPm9OTFo
 | 
					mYYFZUOV+OQ8AngOCdjROsPC0KiEfMvEaEM3NQl58u6QL7G7QsErKViiNPm9OTFo
 | 
				
			||||||
6HF5JijfWzK7haHFuRMEsgI4VwIY.....LorV1ovjwKBgAJR1m8dYKemfaW8P9YZ
 | 
					6HF5JijfWzK7haHFuRMEsgI4VwIYy...fLorV1ovjwKBgAJR1m8dYKemfaW8P9YZ
 | 
				
			||||||
Uux7lwIFqF+yI201HpZXX+IJK4g1izq490AmXDuGb2bxMCYVZbJ8vSzvCJG8BiRC
 | 
					Uux7lwIFqF+yI201HpZXX+IJK4g1izq490AmXDuGb2bxMCYVZbJ8vSzvCJG8BiRC
 | 
				
			||||||
+nF62itPAclUtpsEMn5YE4BjZ6c4schFC/5q0C8esteORR3MX3qjSJzIXqftDMZ9
 | 
					+nF62itPAclUtpsEMn5YE4BjZ6c4schFC/5q0C8esteORR3MX3qjSJzIXqftDMZ9
 | 
				
			||||||
Q+Z5YZiDoEQKUtLfVaF7R4RV
 | 
					Q+Z5YZiDoEQKUtLfVaF7R4RV
 | 
				
			||||||
@ -149,15 +119,18 @@ Rasha.export({ jwk: jwk, format: 'ssh' }).then(function (pub) {
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCba21UHE.....Q02P1Eamz/nT4I3 rsa@localhost
 | 
					ssh-rsa TODO-TODO-TODO RSA-2048@localhost
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`public: 'true'`:
 | 
					`public: 'true'`:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If a private key is used as input, a private key will be output.
 | 
					If a private key is used as input, a private key will be output.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you'd like to output a public key instead you can pass `public: true`.
 | 
					If you'd like to output a public key instead you can pass `public: true`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!--
 | 
				
			||||||
or `format: 'spki'`.
 | 
					or `format: 'spki'`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```js
 | 
					```js
 | 
				
			||||||
@ -168,27 +141,21 @@ Rasha.export({ jwk: jwk, public: true }).then(function (pem) {
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
-----BEGIN PUBLIC KEY-----
 | 
					-----BEGIN RSA PUBLIC KEY-----
 | 
				
			||||||
MIIBCgKCAQEAm2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhDNzUJ
 | 
					MIIBCgKCAQEAm2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhDNzUJ
 | 
				
			||||||
efLukC+xu0LBKylYojT5vTkxaOhx.....TmzCh2ikrwTMja7mUdBJf2bK3By5AB0
 | 
					efLukC+xu0LBKylYojT5vTkxaOhxe...eTmzCh2ikrwTMja7mUdBJf2bK3By5AB0
 | 
				
			||||||
Qi49OykUCfNZeQlEz7UNNj9RGps/50+CNwIDAQAB
 | 
					Qi49OykUCfNZeQlEz7UNNj9RGps/50+CNwIDAQAB
 | 
				
			||||||
-----END PUBLIC KEY-----
 | 
					-----END RSA PUBLIC KEY-----
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## JWK Thumbprint
 | 
					-->
 | 
				
			||||||
 | 
					 | 
				
			||||||
```js
 | 
					 | 
				
			||||||
Rasha.thumbprint({ jwk: jwk }).then(function (thumbprint) {
 | 
					 | 
				
			||||||
  console.log(thumbprint);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Testing
 | 
					Testing
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
All cases are tested in `test.sh`.
 | 
					<!-- All cases are tested in `test.sh`. -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can compare these keys to the ones that you get from OpenSSL, OpenSSH/ssh-keygen, and WebCrypto:
 | 
					You can compare these keys to the ones that you get from OpenSSL, ssh-keygen, and WebCrypto:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
# Generate 2048-bit RSA Keypair
 | 
					# Generate 2048-bit RSA Keypair
 | 
				
			||||||
@ -210,18 +177,16 @@ ssh-keygen -f ./pub-rsa-2048.spki.pem -i -mPKCS8 > ./pub-rsa-2048.ssh.pub
 | 
				
			|||||||
Goals of this project
 | 
					Goals of this project
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Focused support for 2048-bit and 4096-bit RSA keypairs (although any size is technically supported)
 | 
					 | 
				
			||||||
* Zero Dependencies
 | 
					* Zero Dependencies
 | 
				
			||||||
* VanillaJS
 | 
					* Focused support for 2048-bit and 4096-bit RSA keypairs (although any size is technically supported)
 | 
				
			||||||
* Quality Code: Good comments and tests
 | 
					* Convert both ways
 | 
				
			||||||
* Convert both ways: PEM-to-JWK and JWK-to-PEM (also supports SSH pub files)
 | 
					 | 
				
			||||||
* Browser support as well (TODO)
 | 
					* Browser support as well (TODO)
 | 
				
			||||||
* OpenSSL, ssh-keygen, and WebCrypto compatibility
 | 
					* OpenSSL, ssh-keygen, and WebCrypto compatibility
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Legal
 | 
					Legal
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js) |
 | 
					Licensed MPL-2.0
 | 
				
			||||||
MPL-2.0 |
 | 
					
 | 
				
			||||||
[Terms of Use](https://therootcompany.com/legal/#terms) |
 | 
					[Terms of Use](https://therootcompany.com/legal/#terms) |
 | 
				
			||||||
[Privacy Policy](https://therootcompany.com/legal/#privacy)
 | 
					[Privacy Policy](https://therootcompany.com/legal/#privacy)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										68
									
								
								bin/rasha.js
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								bin/rasha.js
									
									
									
									
									
								
							@ -8,36 +8,7 @@ var ASN1 = require('../lib/asn1.js');
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var infile = process.argv[2];
 | 
					var infile = process.argv[2];
 | 
				
			||||||
var format = process.argv[3];
 | 
					var format = process.argv[3];
 | 
				
			||||||
var msg = process.argv[4];
 | 
					 | 
				
			||||||
var sign;
 | 
					 | 
				
			||||||
if ('sign' === format) {
 | 
					 | 
				
			||||||
  sign = true;
 | 
					 | 
				
			||||||
  format = 'pkcs8';
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (!infile) {
 | 
					 | 
				
			||||||
  infile = 'jwk';
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (-1 !== [ 'jwk', 'pem', 'json', 'der', 'pkcs1', 'pkcs8', 'spki' ].indexOf(infile)) {
 | 
					 | 
				
			||||||
  console.info("Generating new key...");
 | 
					 | 
				
			||||||
  Rasha.generate({
 | 
					 | 
				
			||||||
    format: infile
 | 
					 | 
				
			||||||
  , modulusLength: parseInt(format, 10) || 2048
 | 
					 | 
				
			||||||
  , encoding: parseInt(format, 10) ? null : format
 | 
					 | 
				
			||||||
  }).then(function (key) {
 | 
					 | 
				
			||||||
    if ('der' === infile || 'der' === format) {
 | 
					 | 
				
			||||||
      key.private = key.private.toString('binary');
 | 
					 | 
				
			||||||
      key.public = key.public.toString('binary');
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    console.info(key.private);
 | 
					 | 
				
			||||||
    console.info(key.public);
 | 
					 | 
				
			||||||
  }).catch(function (err) {
 | 
					 | 
				
			||||||
    console.error(err);
 | 
					 | 
				
			||||||
    process.exit(1);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  return;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
var key = fs.readFileSync(infile, 'ascii');
 | 
					var key = fs.readFileSync(infile, 'ascii');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
try {
 | 
					try {
 | 
				
			||||||
@ -46,24 +17,13 @@ try {
 | 
				
			|||||||
  // ignore
 | 
					  // ignore
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var thumbprint = ('thumbprint' === format);
 | 
					 | 
				
			||||||
if (thumbprint) {
 | 
					 | 
				
			||||||
  format = 'public';
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if ('string' === typeof key) {
 | 
					if ('string' === typeof key) {
 | 
				
			||||||
  if (thumbprint) {
 | 
					 | 
				
			||||||
    Rasha.thumbprint({ pem: key }).then(console.info);
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if ('tpl' === format) {
 | 
					  if ('tpl' === format) {
 | 
				
			||||||
    var block = PEM.parseBlock(key);
 | 
					    var block = PEM.parseBlock(key);
 | 
				
			||||||
    var asn1 = ASN1.parse(block.der);
 | 
					    var asn1 = ASN1.parse(block.der);
 | 
				
			||||||
    ASN1.tpl(asn1);
 | 
					    ASN1.tpl(asn1);
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (sign) { signMessage(key, msg); return; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var pub = (-1 !== [ 'public', 'spki', 'pkix' ].indexOf(format));
 | 
					  var pub = (-1 !== [ 'public', 'spki', 'pkix' ].indexOf(format));
 | 
				
			||||||
  Rasha.import({ pem: key, public: (pub || format) }).then(function (jwk) {
 | 
					  Rasha.import({ pem: key, public: (pub || format) }).then(function (jwk) {
 | 
				
			||||||
    console.info(JSON.stringify(jwk, null, 2));
 | 
					    console.info(JSON.stringify(jwk, null, 2));
 | 
				
			||||||
@ -72,38 +32,10 @@ if ('string' === typeof key) {
 | 
				
			|||||||
    process.exit(1);
 | 
					    process.exit(1);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
} else {
 | 
					} else {
 | 
				
			||||||
  if (thumbprint) {
 | 
					 | 
				
			||||||
    Rasha.thumbprint({ jwk: key }).then(console.info);
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  Rasha.export({ jwk: key, format: format }).then(function (pem) {
 | 
					  Rasha.export({ jwk: key, format: format }).then(function (pem) {
 | 
				
			||||||
    if (sign) { signMessage(pem, msg); return; }
 | 
					 | 
				
			||||||
    console.info(pem);
 | 
					    console.info(pem);
 | 
				
			||||||
  }).catch(function (err) {
 | 
					  }).catch(function (err) {
 | 
				
			||||||
    console.error(err);
 | 
					    console.error(err);
 | 
				
			||||||
    process.exit(2);
 | 
					    process.exit(2);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
function signMessage(pem, name) {
 | 
					 | 
				
			||||||
  var msg;
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    msg = fs.readFileSync(name);
 | 
					 | 
				
			||||||
  } catch(e) {
 | 
					 | 
				
			||||||
    console.warn("[info] input string did not exist as a file, signing the string itself");
 | 
					 | 
				
			||||||
    msg = Buffer.from(name, 'binary');
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  var crypto = require('crypto');
 | 
					 | 
				
			||||||
  var sign = crypto.createSign('SHA256');
 | 
					 | 
				
			||||||
  sign.write(msg)
 | 
					 | 
				
			||||||
  sign.end()
 | 
					 | 
				
			||||||
  var buf = sign.sign(pem);
 | 
					 | 
				
			||||||
  console.info(buf.toString('base64'));
 | 
					 | 
				
			||||||
  /*
 | 
					 | 
				
			||||||
  Rasha.sign({ pem: pem, message: msg, alg: 'SHA256' }).then(function (sig) {
 | 
					 | 
				
			||||||
  }).catch(function () {
 | 
					 | 
				
			||||||
    console.error(err);
 | 
					 | 
				
			||||||
    process.exit(3);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  */
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								index.js
									
									
									
									
									
								
							@ -1,2 +1,2 @@
 | 
				
			|||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
module.exports = require('./lib/rsa.js');
 | 
					module.exports = require('./lib/rasha.js');
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										78
									
								
								lib/asn1.js
									
									
									
									
									
								
							
							
						
						
									
										78
									
								
								lib/asn1.js
									
									
									
									
									
								
							@ -76,14 +76,13 @@ ASN1.BitStr = function BITSTR() {
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ASN1.ELOOP = "uASN1.js Error: iterated over 15+ elements (probably a malformed file)";
 | 
					ASN1.ELOOP = "uASN1.js Error: iterated over 15+ elements (probably a malformed file)";
 | 
				
			||||||
ASN1.EDEEP = "uASN1.js Error: element nested 20+ layers deep (probably a malformed file)";
 | 
					ASN1.EDEEP = "uASN1.js Error: element nested 10+ layers deep (probably a malformed file)";
 | 
				
			||||||
// Container Types are Sequence 0x30, Octect String 0x04, Array? (0xA0, 0xA1)
 | 
					// Container Types are Sequence 0x30, Octect String 0x04, Array? (0xA0, 0xA1)
 | 
				
			||||||
// Value Types are Integer 0x02, Bit String 0x03, Null 0x05, Object ID 0x06,
 | 
					// Value Types are Integer 0x02, Bit String 0x03, Null 0x05, Object ID 0x06,
 | 
				
			||||||
// Sometimes Bit String is used as a container (RSA Pub Spki)
 | 
					// Sometimes Bit String is used as a container (RSA Pub Spki)
 | 
				
			||||||
ASN1.VTYPES = [ 0x02, 0x03, 0x05, 0x06, 0x0c, 0x82 ];
 | 
					ASN1.VTYPES = [ 0x02, 0x03, 0x05, 0x06 ];
 | 
				
			||||||
ASN1.parse = function parseAsn1(buf, depth, ws) {
 | 
					ASN1.parse = function parseAsn1(buf, depth) {
 | 
				
			||||||
  if (!ws) { ws = ''; }
 | 
					  if (depth >= 10) { throw new Error(ASN1.EDEEP); }
 | 
				
			||||||
  if (depth >= 20) { throw new Error(ASN1.EDEEP); }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
 | 
					  var index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
 | 
				
			||||||
  var asn1 = { type: buf[0], lengthSize: 0, length: buf[1] };
 | 
					  var asn1 = { type: buf[0], lengthSize: 0, length: buf[1] };
 | 
				
			||||||
@ -96,7 +95,7 @@ ASN1.parse = function parseAsn1(buf, depth, ws) {
 | 
				
			|||||||
  if (0x80 & asn1.length) {
 | 
					  if (0x80 & asn1.length) {
 | 
				
			||||||
    asn1.lengthSize = 0x7f & asn1.length;
 | 
					    asn1.lengthSize = 0x7f & asn1.length;
 | 
				
			||||||
    // I think that buf->hex->int solves the problem of Endianness... not sure
 | 
					    // I think that buf->hex->int solves the problem of Endianness... not sure
 | 
				
			||||||
    asn1.length = parseInt(Enc.bufToHex(buf.slice(index, index + asn1.lengthSize)), 16);
 | 
					    asn1.length = parseInt(buf.slice(index, index + asn1.lengthSize).toString('hex'), 16);
 | 
				
			||||||
    index += asn1.lengthSize;
 | 
					    index += asn1.lengthSize;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -109,9 +108,8 @@ ASN1.parse = function parseAsn1(buf, depth, ws) {
 | 
				
			|||||||
      adjust = -1;
 | 
					      adjust = -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  adjustedLen = asn1.length + adjust;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //console.warn(ws + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
 | 
					  adjustedLen = asn1.length + adjust;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // this is a primitive value type
 | 
					  // this is a primitive value type
 | 
				
			||||||
  if (-1 !== ASN1.VTYPES.indexOf(asn1.type)) {
 | 
					  if (-1 !== ASN1.VTYPES.indexOf(asn1.type)) {
 | 
				
			||||||
@ -120,31 +118,16 @@ ASN1.parse = function parseAsn1(buf, depth, ws) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  asn1.children = [];
 | 
					  asn1.children = [];
 | 
				
			||||||
  //console.warn('1 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', 0);
 | 
					  while (iters < 15 && index <= asn1.length) {
 | 
				
			||||||
  while (iters < 15 && index < (2 + asn1.length + asn1.lengthSize)) {
 | 
					 | 
				
			||||||
    iters += 1;
 | 
					    iters += 1;
 | 
				
			||||||
    child = ASN1.parse(buf.slice(index, index + adjustedLen), (depth || 0) + 1, ws + '  ');
 | 
					    child = ASN1.parse(buf.slice(index, index + adjustedLen), (depth || 0) + 1);
 | 
				
			||||||
    // The numbers don't match up exactly and I don't remember why...
 | 
					 | 
				
			||||||
    // probably something with adjustedLen or some such, but the tests pass
 | 
					 | 
				
			||||||
    index += (2 + child.lengthSize + child.length);
 | 
					    index += (2 + child.lengthSize + child.length);
 | 
				
			||||||
    //console.warn('2 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', (2 + child.lengthSize + child.length));
 | 
					 | 
				
			||||||
    if (index > (2 + asn1.lengthSize + asn1.length)) {
 | 
					 | 
				
			||||||
      console.error(JSON.stringify(asn1, toPrettyHex, 2));
 | 
					 | 
				
			||||||
      throw new Error("Parse error: child value length (" + child.length
 | 
					 | 
				
			||||||
        + ") is greater than remaining parent length (" + (asn1.length - index)
 | 
					 | 
				
			||||||
        + " = " + asn1.length + " - " + index + ")");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    asn1.children.push(child);
 | 
					    asn1.children.push(child);
 | 
				
			||||||
    //console.warn(ws + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (index !== (2 + asn1.lengthSize + asn1.length)) {
 | 
					 | 
				
			||||||
    throw new Error("premature end-of-file (" + 'index: ' + index + ' length: ' + (2 + asn1.lengthSize + asn1.length) + ")");
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (iters >= 15) { throw new Error(ASN1.ELOOP); }
 | 
					  if (iters >= 15) { throw new Error(ASN1.ELOOP); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return asn1;
 | 
					  return asn1;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
function toPrettyHex(k, v) { if ('value' === k) { return '0x' + Enc.bufToHex(v.data); } return v; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
ASN1._stringify = function(asn1) {
 | 
					ASN1._stringify = function(asn1) {
 | 
				
			||||||
@ -153,7 +136,7 @@ ASN1._stringify = function(asn1) {
 | 
				
			|||||||
  var ws = '';
 | 
					  var ws = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function write(asn1) {
 | 
					  function write(asn1) {
 | 
				
			||||||
    console.log(ws, 'ch', Enc.numToHex(asn1.type), asn1.length);
 | 
					    console.log(ws, 'ch', Buffer.from([asn1.type]).toString('hex'), asn1.length);
 | 
				
			||||||
    if (!asn1.children) {
 | 
					    if (!asn1.children) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -170,8 +153,7 @@ ASN1._stringify = function(asn1) {
 | 
				
			|||||||
ASN1.tpl = function (asn1) {
 | 
					ASN1.tpl = function (asn1) {
 | 
				
			||||||
  //console.log(JSON.stringify(asn1, null, 2));
 | 
					  //console.log(JSON.stringify(asn1, null, 2));
 | 
				
			||||||
  //console.log(asn1);
 | 
					  //console.log(asn1);
 | 
				
			||||||
  var sp = '  ';
 | 
					  var ws = '';
 | 
				
			||||||
  var ws = sp;
 | 
					 | 
				
			||||||
  var i = 0;
 | 
					  var i = 0;
 | 
				
			||||||
  var vars = [];
 | 
					  var vars = [];
 | 
				
			||||||
  var str = ws;
 | 
					  var str = ws;
 | 
				
			||||||
@ -181,53 +163,37 @@ ASN1.tpl = function (asn1) {
 | 
				
			|||||||
    var val;
 | 
					    var val;
 | 
				
			||||||
    if ('number' !== typeof k) {
 | 
					    if ('number' !== typeof k) {
 | 
				
			||||||
      // ignore
 | 
					      // ignore
 | 
				
			||||||
    } else {
 | 
					    } else if (k) {
 | 
				
			||||||
      str += ', ';
 | 
					      str += ', ';
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      str += '  ';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (0x02 === asn1.type) {
 | 
					    if (0x02 === asn1.type) {
 | 
				
			||||||
      str += "ASN1.UInt(";
 | 
					      str += "ASN1.UInt(";
 | 
				
			||||||
    } else if (0x03 === asn1.type) {
 | 
					    } else if (0x03 === asn1.type) {
 | 
				
			||||||
      str += "ASN1.BitStr(";
 | 
					      str += "ASN1.BitStr(";
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      str += "ASN1('" + Enc.numToHex(asn1.type) + "'";
 | 
					      str += "ASN1('" + Buffer.from([asn1.type]).toString('hex') + "', ";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!asn1.children) {
 | 
					    if (!asn1.children) {
 | 
				
			||||||
      if (0x05 !== asn1.type) {
 | 
					      val = Buffer.from(asn1.value || '');
 | 
				
			||||||
        if (0x06 !== asn1.type) {
 | 
					      vars.push("// " + val.byteLength + " bytes\nvar tpl" + i + " = '"
 | 
				
			||||||
          val = asn1.value || new Uint8Array(0);
 | 
					        + val.toString('hex') + "';");
 | 
				
			||||||
          vars.push("\n// 0x" + Enc.numToHex(val.byteLength) + " (" + val.byteLength + " bytes)\nopts.tpl" + i + " = '"
 | 
					      str += "tpl" + i + ")";
 | 
				
			||||||
            + Enc.bufToHex(val) + "';");
 | 
					 | 
				
			||||||
          if (0x02 !== asn1.type && 0x03 !== asn1.type) {
 | 
					 | 
				
			||||||
            str += ", ";
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          str += "Enc.bufToHex(opts.tpl" + i + ")";
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          str += ", '" + Enc.bufToHex(asn1.value) + "'";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        console.warn("XXXXXXXXXXXXXXXXXXXXX");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      str += ")";
 | 
					 | 
				
			||||||
      return ;
 | 
					      return ;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    asn1.children.forEach(function (a, j) {
 | 
					    asn1.children.forEach(function (a, j) {
 | 
				
			||||||
      i += 1;
 | 
					      i += 1;
 | 
				
			||||||
      ws += sp;
 | 
					      ws += '\t';
 | 
				
			||||||
      write(a, j);
 | 
					      write(a, j);
 | 
				
			||||||
      ws = ws.slice(sp.length);
 | 
					      ws = ws.slice(1);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    str += "\n" + ws + ")";
 | 
					    str += "\n" + ws + ")";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  write(asn1);
 | 
					  write(asn1);
 | 
				
			||||||
  console.info('var opts = {};');
 | 
					  console.log(vars.join('\n') + '\n');
 | 
				
			||||||
  console.info(vars.join('\n') + '\n');
 | 
					  console.log(str + ';');
 | 
				
			||||||
  console.info();
 | 
					 | 
				
			||||||
  console.info('function buildSchema(opts) {');
 | 
					 | 
				
			||||||
  console.info(sp + 'return Enc.hexToBuf(' + str.slice(3) + ');');
 | 
					 | 
				
			||||||
  console.info('}');
 | 
					 | 
				
			||||||
  console.info();
 | 
					 | 
				
			||||||
  console.info('buildSchema(opts);');
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = ASN1;
 | 
					module.exports = ASN1;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,51 +0,0 @@
 | 
				
			|||||||
'use strict';
 | 
					 | 
				
			||||||
/*global Promise*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var PEM = require('./pem.js');
 | 
					 | 
				
			||||||
var x509 = require('./x509.js');
 | 
					 | 
				
			||||||
var ASN1 = require('./asn1.js');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Hacky-do, wrappy-do
 | 
					 | 
				
			||||||
module.exports.generate = function (opts) {
 | 
					 | 
				
			||||||
  if (!opts) { opts = {}; }
 | 
					 | 
				
			||||||
  return new Promise(function (resolve, reject) {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      var modlen = opts.modulusLength || 2048;
 | 
					 | 
				
			||||||
      var exp = opts.publicExponent || 0x10001;
 | 
					 | 
				
			||||||
      var pair = require('./generate-privkey.js')(modlen,exp);
 | 
					 | 
				
			||||||
      if (pair.private) { resolve(pair); return; }
 | 
					 | 
				
			||||||
      pair = toJwks(pair);
 | 
					 | 
				
			||||||
      resolve({ private: pair.private , public: pair.public });
 | 
					 | 
				
			||||||
    } catch(e) {
 | 
					 | 
				
			||||||
      reject(e);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// PKCS1 to JWK only
 | 
					 | 
				
			||||||
function toJwks(oldpair) {
 | 
					 | 
				
			||||||
  var block = PEM.parseBlock(oldpair.privateKeyPem);
 | 
					 | 
				
			||||||
  var asn1 = ASN1.parse(block.bytes);
 | 
					 | 
				
			||||||
  var jwk = { kty: 'RSA', n: null, e: null };
 | 
					 | 
				
			||||||
  jwk = x509.parsePkcs1(block.bytes, asn1, jwk);
 | 
					 | 
				
			||||||
  return { private: jwk, public: neuter(jwk) };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Copied from rsa.js to prevent circular dep
 | 
					 | 
				
			||||||
var privates = [ 'p', 'q', 'd', 'dp', 'dq', 'qi' ];
 | 
					 | 
				
			||||||
function neuter(priv) {
 | 
					 | 
				
			||||||
  var pub = {};
 | 
					 | 
				
			||||||
  Object.keys(priv).forEach(function (key) {
 | 
					 | 
				
			||||||
    if (!privates.includes(key)) {
 | 
					 | 
				
			||||||
      pub[key] = priv[key];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  return pub;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (require.main === module) {
 | 
					 | 
				
			||||||
  module.exports.generate().then(function (pair) {
 | 
					 | 
				
			||||||
    console.info(JSON.stringify(pair.private, null, 2));
 | 
					 | 
				
			||||||
    console.info(JSON.stringify(pair.public, null, 2));
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -2,41 +2,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var Enc = module.exports;
 | 
					var Enc = module.exports;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Enc.base64ToBuf = function (str) {
 | 
					Enc.bufToHex = function toHex(u8) {
 | 
				
			||||||
  // always convert from urlsafe base64, just in case
 | 
					 | 
				
			||||||
  //return Buffer.from(Enc.urlBase64ToBase64(str)).toString('base64');
 | 
					 | 
				
			||||||
  // node handles urlBase64 automatically
 | 
					 | 
				
			||||||
  return Buffer.from(str, 'base64');
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Enc.base64ToHex = function (b64) {
 | 
					 | 
				
			||||||
  return Enc.bufToHex(Enc.base64ToBuf(b64));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Enc.bufToBase64 = function (u8) {
 | 
					 | 
				
			||||||
  // we want to maintain api compatability with browser APIs,
 | 
					 | 
				
			||||||
  // so we assume that this could be a Uint8Array
 | 
					 | 
				
			||||||
  return Buffer.from(u8).toString('base64');
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
Enc.bufToUint8 = function bufToUint8(buf) {
 | 
					 | 
				
			||||||
  return new Uint8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Enc.bufToUrlBase64 = function (u8) {
 | 
					 | 
				
			||||||
  return Enc.bufToBase64(u8)
 | 
					 | 
				
			||||||
    .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Enc.bufToHex = function (u8) {
 | 
					 | 
				
			||||||
  var hex = [];
 | 
					  var hex = [];
 | 
				
			||||||
  var i, h;
 | 
					  var i, h;
 | 
				
			||||||
  var len = (u8.byteLength || u8.length);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (i = 0; i < len; i += 1) {
 | 
					  for (i = 0; i < u8.byteLength; i += 1) {
 | 
				
			||||||
    h = u8[i].toString(16);
 | 
					    h = u8[i].toString(16);
 | 
				
			||||||
    if (2 !== h.length) { h = '0' + h; }
 | 
					    if (2 !== h.length) { h = '0' + h; }
 | 
				
			||||||
    hex.push(h);
 | 
					    hex.push(h);
 | 
				
			||||||
@ -53,7 +23,7 @@ Enc.hexToBuf = function (hex) {
 | 
				
			|||||||
  return Buffer.from(hex, 'hex');
 | 
					  return Buffer.from(hex, 'hex');
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Enc.numToHex = function (d) {
 | 
					Enc.numToHex = function numToHex(d) {
 | 
				
			||||||
  d = d.toString(16);
 | 
					  d = d.toString(16);
 | 
				
			||||||
  if (d.length % 2) {
 | 
					  if (d.length % 2) {
 | 
				
			||||||
    return '0' + d;
 | 
					    return '0' + d;
 | 
				
			||||||
@ -61,17 +31,37 @@ Enc.numToHex = function (d) {
 | 
				
			|||||||
  return d;
 | 
					  return d;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Enc.base64ToHex = function base64ToHex(b64) {
 | 
				
			||||||
 | 
					  return Enc.bufToHex(Enc.base64ToBuf(b64));
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Enc.bufToBase64 = function toHex(u8) {
 | 
				
			||||||
 | 
					  // we want to maintain api compatability with browser APIs,
 | 
				
			||||||
 | 
					  // so we assume that this could be a Uint8Array
 | 
				
			||||||
 | 
					  return Buffer.from(u8).toString('base64');
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
Enc.strToBase64 = function (str) {
 | 
					Enc.bufToUint8 = function bufToUint8(buf) {
 | 
				
			||||||
  // node automatically can tell the difference
 | 
					  return new Uint8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
 | 
				
			||||||
  // between uc2 (utf-8) strings and binary strings
 | 
					 | 
				
			||||||
  // so we don't have to re-encode the strings
 | 
					 | 
				
			||||||
  return Buffer.from(str).toString('base64');
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Enc.bufToUrlBase64 = function toHex(u8) {
 | 
				
			||||||
 | 
					  return Enc.bufToBase64(u8)
 | 
				
			||||||
 | 
					    .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Enc.strToHex = function strToHex(str) {
 | 
				
			||||||
 | 
					  return Buffer.from(str).toString('hex');
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Enc.strToBuf = function strToBuf(str) {
 | 
				
			||||||
 | 
					  return Buffer.from(str);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
Enc.strToBin = function (str) {
 | 
					Enc.strToBin = function strToBin(str) {
 | 
				
			||||||
  var escstr = encodeURIComponent(str);
 | 
					  var escstr = encodeURIComponent(str);
 | 
				
			||||||
  // replaces any uri escape sequence, such as %0A,
 | 
					  // replaces any uri escape sequence, such as %0A,
 | 
				
			||||||
  // with binary escape, such as 0x0A
 | 
					  // with binary escape, such as 0x0A
 | 
				
			||||||
@ -83,16 +73,17 @@ Enc.strToBin = function (str) {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Enc.strToBuf = function (str) {
 | 
					/*
 | 
				
			||||||
  return Buffer.from(str);
 | 
					Enc.strToBase64 = function strToBase64(str) {
 | 
				
			||||||
};
 | 
					  // node automatically can tell the difference
 | 
				
			||||||
 | 
					  // between uc2 (utf-8) strings and binary strings
 | 
				
			||||||
Enc.strToHex = function (str) {
 | 
					  // so we don't have to re-encode the strings
 | 
				
			||||||
  return Buffer.from(str).toString('hex');
 | 
					  return Buffer.from(str).toString('base64');
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
Enc.urlBase64ToBase64 = function (str) {
 | 
					Enc.urlBase64ToBase64 = function urlsafeBase64ToBase64(str) {
 | 
				
			||||||
  var r = str % 4;
 | 
					  var r = str % 4;
 | 
				
			||||||
  if (2 === r) {
 | 
					  if (2 === r) {
 | 
				
			||||||
    str += '==';
 | 
					    str += '==';
 | 
				
			||||||
@ -102,3 +93,9 @@ Enc.urlBase64ToBase64 = function (str) {
 | 
				
			|||||||
  return str.replace(/-/g, '+').replace(/_/g, '/');
 | 
					  return str.replace(/-/g, '+').replace(/_/g, '/');
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Enc.base64ToBuf = function base64ToBuf(str) {
 | 
				
			||||||
 | 
					  // always convert from urlsafe base64, just in case
 | 
				
			||||||
 | 
					  //return Buffer.from(Enc.urlBase64ToBase64(str)).toString('base64');
 | 
				
			||||||
 | 
					  return Buffer.from(str, 'base64');
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,53 +0,0 @@
 | 
				
			|||||||
// Copyright 2016-2018 AJ ONeal. All rights reserved
 | 
					 | 
				
			||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
					 | 
				
			||||||
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
					 | 
				
			||||||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
					 | 
				
			||||||
'use strict';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module.exports = function (bitlen, exp) {
 | 
					 | 
				
			||||||
  var k = require('node-forge').pki.rsa
 | 
					 | 
				
			||||||
    .generateKeyPair({ bits: bitlen || 2048, e: exp || 0x10001 }).privateKey;
 | 
					 | 
				
			||||||
  var jwk = {
 | 
					 | 
				
			||||||
    kty: "RSA"
 | 
					 | 
				
			||||||
  , n: _toUrlBase64(k.n)
 | 
					 | 
				
			||||||
  , e: _toUrlBase64(k.e)
 | 
					 | 
				
			||||||
  , d: _toUrlBase64(k.d)
 | 
					 | 
				
			||||||
  , p: _toUrlBase64(k.p)
 | 
					 | 
				
			||||||
  , q: _toUrlBase64(k.q)
 | 
					 | 
				
			||||||
  , dp: _toUrlBase64(k.dP)
 | 
					 | 
				
			||||||
  , dq: _toUrlBase64(k.dQ)
 | 
					 | 
				
			||||||
  , qi: _toUrlBase64(k.qInv)
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    private: jwk
 | 
					 | 
				
			||||||
  , public: {
 | 
					 | 
				
			||||||
      kty: jwk.kty
 | 
					 | 
				
			||||||
    , n: jwk.n
 | 
					 | 
				
			||||||
    , e: jwk.e
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function _toUrlBase64(fbn) {
 | 
					 | 
				
			||||||
  var hex = fbn.toRadix(16);
 | 
					 | 
				
			||||||
  if (hex.length % 2) {
 | 
					 | 
				
			||||||
    // Invalid hex string
 | 
					 | 
				
			||||||
    hex = '0' + hex;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  while ('00' === hex.slice(0, 2)) {
 | 
					 | 
				
			||||||
    hex = hex.slice(2);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return Buffer.from(hex, 'hex').toString('base64')
 | 
					 | 
				
			||||||
    .replace(/\+/g, "-")
 | 
					 | 
				
			||||||
    .replace(/\//g, "_")
 | 
					 | 
				
			||||||
    .replace(/=/g,"")
 | 
					 | 
				
			||||||
  ;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (require.main === module) {
 | 
					 | 
				
			||||||
  var keypair = module.exports(2048, 0x10001);
 | 
					 | 
				
			||||||
  console.info(keypair.private);
 | 
					 | 
				
			||||||
  console.warn(keypair.public);
 | 
					 | 
				
			||||||
  //console.info(keypair.privateKeyJwk);
 | 
					 | 
				
			||||||
  //console.warn(keypair.publicKeyJwk);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,23 +0,0 @@
 | 
				
			|||||||
// Copyright 2016-2018 AJ ONeal. All rights reserved
 | 
					 | 
				
			||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
					 | 
				
			||||||
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
					 | 
				
			||||||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
					 | 
				
			||||||
'use strict';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module.exports = function (bitlen, exp) {
 | 
					 | 
				
			||||||
  var keypair = require('crypto').generateKeyPairSync(
 | 
					 | 
				
			||||||
    'rsa'
 | 
					 | 
				
			||||||
  , { modulusLength: bitlen
 | 
					 | 
				
			||||||
    , publicExponent: exp
 | 
					 | 
				
			||||||
    , privateKeyEncoding: { type: 'pkcs1', format: 'pem' }
 | 
					 | 
				
			||||||
    , publicKeyEncoding: { type: 'pkcs1', format: 'pem' }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
  var result = { privateKeyPem: keypair.privateKey.trim() };
 | 
					 | 
				
			||||||
  return result;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (require.main === module) {
 | 
					 | 
				
			||||||
  var keypair = module.exports(2048, 0x10001);
 | 
					 | 
				
			||||||
  console.info(keypair.privateKeyPem);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,22 +0,0 @@
 | 
				
			|||||||
// Copyright 2016-2018 AJ ONeal. All rights reserved
 | 
					 | 
				
			||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
					 | 
				
			||||||
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
					 | 
				
			||||||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
					 | 
				
			||||||
'use strict';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module.exports = function (bitlen, exp) {
 | 
					 | 
				
			||||||
  var ursa;
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    ursa = require('ursa');
 | 
					 | 
				
			||||||
  } catch(e) {
 | 
					 | 
				
			||||||
    ursa = require('ursa-optional');
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  var keypair = ursa.generatePrivateKey(bitlen, exp);
 | 
					 | 
				
			||||||
  var result = { privateKeyPem: keypair.toPrivatePem().toString('ascii').trim() };
 | 
					 | 
				
			||||||
  return result;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (require.main === module) {
 | 
					 | 
				
			||||||
  var keypair = module.exports(2048, 0x10001);
 | 
					 | 
				
			||||||
  console.info(keypair.privateKeyPem);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,64 +0,0 @@
 | 
				
			|||||||
// Copyright 2016-2018 AJ ONeal. All rights reserved
 | 
					 | 
				
			||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
					 | 
				
			||||||
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
					 | 
				
			||||||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
					 | 
				
			||||||
'use strict';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var oldver = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module.exports = function (bitlen, exp) {
 | 
					 | 
				
			||||||
  bitlen = parseInt(bitlen, 10) || 2048;
 | 
					 | 
				
			||||||
  exp = parseInt(exp, 10) || 65537;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    return require('./generate-privkey-node.js')(bitlen, exp);
 | 
					 | 
				
			||||||
  } catch(e) {
 | 
					 | 
				
			||||||
    if (!/generateKeyPairSync is not a function/.test(e.message)) {
 | 
					 | 
				
			||||||
      throw e;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
      return require('./generate-privkey-ursa.js')(bitlen, exp);
 | 
					 | 
				
			||||||
    } catch(e) {
 | 
					 | 
				
			||||||
      if (e.code !== 'MODULE_NOT_FOUND') {
 | 
					 | 
				
			||||||
        console.error("[rsa-compat] Unexpected error when using 'ursa':");
 | 
					 | 
				
			||||||
        console.error(e);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (!oldver) {
 | 
					 | 
				
			||||||
        oldver = true;
 | 
					 | 
				
			||||||
        console.warn("[WARN] rsa-compat: Your version of node does not have crypto.generateKeyPair()");
 | 
					 | 
				
			||||||
        console.warn("[WARN] rsa-compat: Please update to node >= v10.12 or 'npm install --save ursa node-forge'");
 | 
					 | 
				
			||||||
        console.warn("[WARN] rsa-compat: Using node-forge as a fallback may be unacceptably slow.");
 | 
					 | 
				
			||||||
        if (/arm|mips/i.test(require('os').arch)) {
 | 
					 | 
				
			||||||
          console.warn("================================================================");
 | 
					 | 
				
			||||||
          console.warn("                         WARNING");
 | 
					 | 
				
			||||||
          console.warn("================================================================");
 | 
					 | 
				
			||||||
          console.warn("");
 | 
					 | 
				
			||||||
          console.warn("WARNING: You are generating an RSA key using pure JavaScript on");
 | 
					 | 
				
			||||||
          console.warn("         a VERY SLOW cpu. This could take DOZENS of minutes!");
 | 
					 | 
				
			||||||
          console.warn("");
 | 
					 | 
				
			||||||
          console.warn("         We recommend installing node >= v10.12, or 'gcc' and 'ursa'");
 | 
					 | 
				
			||||||
          console.warn("");
 | 
					 | 
				
			||||||
          console.warn("EXAMPLE:");
 | 
					 | 
				
			||||||
          console.warn("");
 | 
					 | 
				
			||||||
          console.warn("        sudo apt-get install build-essential && npm install ursa");
 | 
					 | 
				
			||||||
          console.warn("");
 | 
					 | 
				
			||||||
          console.warn("================================================================");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      try {
 | 
					 | 
				
			||||||
        return require('./generate-privkey-forge.js')(bitlen, exp);
 | 
					 | 
				
			||||||
      } catch(e) {
 | 
					 | 
				
			||||||
        if (e.code !== 'MODULE_NOT_FOUND') {
 | 
					 | 
				
			||||||
          throw e;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        console.error("[ERROR] rsa-compat: could not generate a private key.");
 | 
					 | 
				
			||||||
        console.error("None of crypto.generateKeyPair, ursa, nor node-forge are present");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (require.main === module) {
 | 
					 | 
				
			||||||
  var keypair = module.exports(2048, 0x10001);
 | 
					 | 
				
			||||||
  console.info(keypair.privateKeyPem);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										41
									
								
								lib/pem.js
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								lib/pem.js
									
									
									
									
									
								
							@ -3,24 +3,43 @@
 | 
				
			|||||||
var PEM = module.exports;
 | 
					var PEM = module.exports;
 | 
				
			||||||
var Enc = require('./encoding.js');
 | 
					var Enc = require('./encoding.js');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PEM.RSA_OBJID = '06 09 2A864886F70D010101'
 | 
				
			||||||
 | 
					  .replace(/\s+/g, '').toLowerCase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PEM.parseBlock = function pemToDer(pem) {
 | 
					PEM.parseBlock = function pemToDer(pem) {
 | 
				
			||||||
  var lines = pem.trim().split(/\n/);
 | 
					  var typ;
 | 
				
			||||||
  var end = lines.length - 1;
 | 
					  var pub;
 | 
				
			||||||
  var head = lines[0].match(/-----BEGIN (.*)-----/);
 | 
					  var hex;
 | 
				
			||||||
  var foot = lines[end].match(/-----END (.*)-----/);
 | 
					  var der = Enc.base64ToBuf(pem.split(/\n/).filter(function (line, i) {
 | 
				
			||||||
 | 
					    if (0 === i) {
 | 
				
			||||||
  if (head) {
 | 
					      if (/ PUBLIC /.test(line)) {
 | 
				
			||||||
    lines = lines.slice(1, end);
 | 
					        pub = true;
 | 
				
			||||||
    head = head[1];
 | 
					      } else if (/ PRIVATE /.test(line)) {
 | 
				
			||||||
    if (head !== foot[1]) {
 | 
					        pub = false;
 | 
				
			||||||
      throw new Error("headers and footers do not match");
 | 
					      }
 | 
				
			||||||
 | 
					      if (/ RSA /.test(line)) {
 | 
				
			||||||
 | 
					        typ = 'RSA';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return !/---/.test(line);
 | 
				
			||||||
 | 
					  }).join(''));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return { type: head, bytes: Enc.base64ToBuf(lines.join('')) };
 | 
					  if (!typ) {
 | 
				
			||||||
 | 
					    hex = Enc.bufToHex(der);
 | 
				
			||||||
 | 
					    if (-1 !== hex.indexOf(PEM.RSA_OBJID)) {
 | 
				
			||||||
 | 
					      typ = 'RSA';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!typ) {
 | 
				
			||||||
 | 
					    console.warn("Definitely not an RSA PKCS#8 because there's no RSA Object ID in the DER body.");
 | 
				
			||||||
 | 
					    console.warn("Probably not an RSA PKCS#1 because 'RSA' wasn't in the PEM type string.");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return { kty: typ, pub: pub, der: der };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PEM.packBlock = function (opts) {
 | 
					PEM.packBlock = function (opts) {
 | 
				
			||||||
 | 
					  // TODO allow for headers?
 | 
				
			||||||
  return '-----BEGIN ' + opts.type + '-----\n'
 | 
					  return '-----BEGIN ' + opts.type + '-----\n'
 | 
				
			||||||
    + Enc.bufToBase64(opts.bytes).match(/.{1,64}/g).join('\n') + '\n'
 | 
					    + Enc.bufToBase64(opts.bytes).match(/.{1,64}/g).join('\n') + '\n'
 | 
				
			||||||
    + '-----END ' + opts.type + '-----'
 | 
					    + '-----END ' + opts.type + '-----'
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										121
									
								
								lib/rasha.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								lib/rasha.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var RSA = module.exports;
 | 
				
			||||||
 | 
					var SSH = require('./ssh.js');
 | 
				
			||||||
 | 
					var PEM = require('./pem.js');
 | 
				
			||||||
 | 
					var x509 = require('./x509.js');
 | 
				
			||||||
 | 
					var ASN1 = require('./asn1.js');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*global Promise*/
 | 
				
			||||||
 | 
					RSA.parse = function parseRsa(opts) {
 | 
				
			||||||
 | 
					  return Promise.resolve().then(function () {
 | 
				
			||||||
 | 
					    if (!opts || !opts.pem || 'string' !== typeof opts.pem) {
 | 
				
			||||||
 | 
					      throw new Error("must pass { pem: pem } as a string");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var jwk = { kty: 'RSA', n: null, e: null };
 | 
				
			||||||
 | 
					    if (0 === opts.pem.indexOf('ssh-rsa ')) {
 | 
				
			||||||
 | 
					      return SSH.parse(opts.pem, jwk);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var pem = opts.pem;
 | 
				
			||||||
 | 
					    var block = PEM.parseBlock(pem);
 | 
				
			||||||
 | 
					    //var hex = toHex(u8);
 | 
				
			||||||
 | 
					    var asn1 = ASN1.parse(block.der);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var meta = x509.guess(block.der, asn1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ('pkcs1' === meta.format) {
 | 
				
			||||||
 | 
					      jwk = x509.parsePkcs1(block.der, asn1, jwk);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      jwk = x509.parsePkcs8(block.der, asn1, jwk);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (opts.public) {
 | 
				
			||||||
 | 
					      jwk = RSA.nueter(jwk);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return jwk;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					RSA.toJwk = RSA.import = RSA.parse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RSA.pack = function (opts) {
 | 
				
			||||||
 | 
					  return Promise.resolve().then(function () {
 | 
				
			||||||
 | 
					    if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {
 | 
				
			||||||
 | 
					      throw new Error("must pass { jwk: jwk }");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var jwk = JSON.parse(JSON.stringify(opts.jwk));
 | 
				
			||||||
 | 
					    var format = opts.format;
 | 
				
			||||||
 | 
					    var pub = opts.public;
 | 
				
			||||||
 | 
					    if (pub || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) {
 | 
				
			||||||
 | 
					      jwk = RSA.nueter(jwk);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if ('RSA' !== jwk.kty) {
 | 
				
			||||||
 | 
					      throw new Error("options.jwk.kty must be 'RSA' for RSA keys");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!jwk.p) {
 | 
				
			||||||
 | 
					      // TODO test for n and e
 | 
				
			||||||
 | 
					      pub = true;
 | 
				
			||||||
 | 
					      if (!format || 'pkcs1' === format) {
 | 
				
			||||||
 | 
					        format = 'pkcs1';
 | 
				
			||||||
 | 
					      } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
 | 
				
			||||||
 | 
					        format = 'spki';
 | 
				
			||||||
 | 
					      } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
 | 
				
			||||||
 | 
					        format = 'ssh';
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        throw new Error("options.format must be 'spki', 'pkcs1', or 'ssh' for public RSA keys, not ("
 | 
				
			||||||
 | 
					          + typeof format + ") " + format);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // TODO test for all necessary keys (d, p, q ...)
 | 
				
			||||||
 | 
					      if (!format || 'pkcs1' === format) {
 | 
				
			||||||
 | 
					        format = 'pkcs1';
 | 
				
			||||||
 | 
					      } else if ('pkcs8' !== format) {
 | 
				
			||||||
 | 
					        throw new Error("options.format must be 'pkcs1' or 'pkcs8' for private RSA keys");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ('pkcs1' === format) {
 | 
				
			||||||
 | 
					      if (jwk.d) {
 | 
				
			||||||
 | 
					        return PEM.packBlock({ type: "RSA PRIVATE KEY", bytes: x509.packPkcs1(jwk) });
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return PEM.packBlock({ type: "RSA PUBLIC KEY", bytes: x509.packPkcs1(jwk) });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else if ('pkcs8' === format) {
 | 
				
			||||||
 | 
					      return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) });
 | 
				
			||||||
 | 
					    } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
 | 
				
			||||||
 | 
					      return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) });
 | 
				
			||||||
 | 
					    } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
 | 
				
			||||||
 | 
					      return SSH.pack({ jwk: jwk, comment: opts.comment });
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      throw new Error("Sanity Error: reached unreachable code block with format: " + format);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					RSA.toPem = RSA.export = RSA.pack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// snip the _private_ parts... hAHAHAHA!
 | 
				
			||||||
 | 
					RSA.nueter = function (jwk) {
 | 
				
			||||||
 | 
					  // (snip rather than new object to keep potential extra data)
 | 
				
			||||||
 | 
					  // otherwise we could just do this:
 | 
				
			||||||
 | 
					  // return { kty: jwk.kty, n: jwk.n, e: jwk.e };
 | 
				
			||||||
 | 
					  [ 'p', 'q', 'd', 'dp', 'dq', 'qi' ].forEach(function (key) {
 | 
				
			||||||
 | 
					    if (key in jwk) { jwk[key] = undefined; }
 | 
				
			||||||
 | 
					    return jwk;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  return jwk;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										225
									
								
								lib/rsa.js
									
									
									
									
									
								
							
							
						
						
									
										225
									
								
								lib/rsa.js
									
									
									
									
									
								
							@ -1,225 +0,0 @@
 | 
				
			|||||||
'use strict';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var RSA = module.exports;
 | 
					 | 
				
			||||||
var SSH = require('./ssh.js');
 | 
					 | 
				
			||||||
var PEM = require('./pem.js');
 | 
					 | 
				
			||||||
var x509 = require('./x509.js');
 | 
					 | 
				
			||||||
var ASN1 = require('./asn1.js');
 | 
					 | 
				
			||||||
var Enc = require('./encoding.js');
 | 
					 | 
				
			||||||
var Crypto = require('./crypto.js');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*global Promise*/
 | 
					 | 
				
			||||||
RSA.generate = function (opts) {
 | 
					 | 
				
			||||||
  opts.kty = "RSA";
 | 
					 | 
				
			||||||
  return Crypto.generate(opts).then(function (pair) {
 | 
					 | 
				
			||||||
    var format = opts.format;
 | 
					 | 
				
			||||||
    var encoding = opts.encoding;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // The easy way
 | 
					 | 
				
			||||||
    if ('json' === format && !encoding) {
 | 
					 | 
				
			||||||
      format = 'jwk';
 | 
					 | 
				
			||||||
      encoding = 'json';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (('jwk' === format || !format) && ('json' === encoding || !encoding)) { return pair; }
 | 
					 | 
				
			||||||
    if ('jwk' === format || 'json' === encoding) {
 | 
					 | 
				
			||||||
      throw new Error("format '" + format + "' is incompatible with encoding '" + encoding + "'");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // The... less easy way
 | 
					 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
    var priv;
 | 
					 | 
				
			||||||
    var pub;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ('spki' === format || 'pkcs8' === format) {
 | 
					 | 
				
			||||||
      format = 'pkcs8';
 | 
					 | 
				
			||||||
      pub = 'spki';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ('pem' === format) {
 | 
					 | 
				
			||||||
      format = 'pkcs1';
 | 
					 | 
				
			||||||
      encoding = 'pem';
 | 
					 | 
				
			||||||
    } else if ('der' === format) {
 | 
					 | 
				
			||||||
      format = 'pkcs1';
 | 
					 | 
				
			||||||
      encoding = 'der';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    priv = format;
 | 
					 | 
				
			||||||
    pub = pub || format;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!encoding) {
 | 
					 | 
				
			||||||
      encoding = 'pem';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (priv) {
 | 
					 | 
				
			||||||
      priv = { type: priv, format: encoding };
 | 
					 | 
				
			||||||
      pub = { type: pub, format: encoding };
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      // jwk
 | 
					 | 
				
			||||||
      priv = { type: 'pkcs1', format: 'pem' };
 | 
					 | 
				
			||||||
      pub = { type: 'pkcs1', format: 'pem' };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    if (('pem' === format || 'der' === format) && !encoding) {
 | 
					 | 
				
			||||||
      encoding = format;
 | 
					 | 
				
			||||||
      format = 'pkcs1';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var exOpts = { jwk: pair.private, format: format, encoding: encoding };
 | 
					 | 
				
			||||||
    return RSA.export(exOpts).then(function (priv) {
 | 
					 | 
				
			||||||
      exOpts.public = true;
 | 
					 | 
				
			||||||
      if ('pkcs8' === exOpts.format) { exOpts.format = 'spki'; }
 | 
					 | 
				
			||||||
      return RSA.export(exOpts).then(function (pub) {
 | 
					 | 
				
			||||||
        return { private: priv, public: pub };
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RSA.importSync = function (opts) {
 | 
					 | 
				
			||||||
  if (!opts || !opts.pem || 'string' !== typeof opts.pem) {
 | 
					 | 
				
			||||||
    throw new Error("must pass { pem: pem } as a string");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var jwk = { kty: 'RSA', n: null, e: null };
 | 
					 | 
				
			||||||
  if (0 === opts.pem.indexOf('ssh-rsa ')) {
 | 
					 | 
				
			||||||
    return SSH.parse(opts.pem, jwk);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  var pem = opts.pem;
 | 
					 | 
				
			||||||
  var block = PEM.parseBlock(pem);
 | 
					 | 
				
			||||||
  //var hex = toHex(u8);
 | 
					 | 
				
			||||||
  var asn1 = ASN1.parse(block.bytes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var meta = x509.guess(block.bytes, asn1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if ('pkcs1' === meta.format) {
 | 
					 | 
				
			||||||
    jwk = x509.parsePkcs1(block.bytes, asn1, jwk);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    jwk = x509.parsePkcs8(block.bytes, asn1, jwk);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (opts.public) {
 | 
					 | 
				
			||||||
    jwk = RSA.neuter(jwk);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return jwk;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
RSA.parse = function parseRsa(opts) {
 | 
					 | 
				
			||||||
  // wrapped in a promise for API compatibility
 | 
					 | 
				
			||||||
  // with the forthcoming browser version
 | 
					 | 
				
			||||||
  // (and potential future native node capability)
 | 
					 | 
				
			||||||
  return Promise.resolve().then(function () {
 | 
					 | 
				
			||||||
    return RSA.importSync(opts);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
RSA.toJwk = RSA.import = RSA.parse;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RSA.exportSync = function (opts) {
 | 
					 | 
				
			||||||
  if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {
 | 
					 | 
				
			||||||
    throw new Error("must pass { jwk: jwk }");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  var jwk = JSON.parse(JSON.stringify(opts.jwk));
 | 
					 | 
				
			||||||
  var format = opts.format;
 | 
					 | 
				
			||||||
  var pub = opts.public;
 | 
					 | 
				
			||||||
  if (pub || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) {
 | 
					 | 
				
			||||||
    jwk = RSA.neuter(jwk);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if ('RSA' !== jwk.kty) {
 | 
					 | 
				
			||||||
    throw new Error("options.jwk.kty must be 'RSA' for RSA keys");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (!jwk.p) {
 | 
					 | 
				
			||||||
    // TODO test for n and e
 | 
					 | 
				
			||||||
    pub = true;
 | 
					 | 
				
			||||||
    if (!format || 'pkcs1' === format) {
 | 
					 | 
				
			||||||
      format = 'pkcs1';
 | 
					 | 
				
			||||||
    } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
 | 
					 | 
				
			||||||
      format = 'spki';
 | 
					 | 
				
			||||||
    } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
 | 
					 | 
				
			||||||
      format = 'ssh';
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      throw new Error("options.format must be 'spki', 'pkcs1', or 'ssh' for public RSA keys, not ("
 | 
					 | 
				
			||||||
        + typeof format + ") " + format);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    // TODO test for all necessary keys (d, p, q ...)
 | 
					 | 
				
			||||||
    if (!format || 'pkcs1' === format) {
 | 
					 | 
				
			||||||
      format = 'pkcs1';
 | 
					 | 
				
			||||||
    } else if ('pkcs8' !== format) {
 | 
					 | 
				
			||||||
      throw new Error("options.format must be 'pkcs1' or 'pkcs8' for private RSA keys");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if ('pkcs1' === format) {
 | 
					 | 
				
			||||||
    if (jwk.d) {
 | 
					 | 
				
			||||||
      return PEM.packBlock({ type: "RSA PRIVATE KEY", bytes: x509.packPkcs1(jwk) });
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      return PEM.packBlock({ type: "RSA PUBLIC KEY", bytes: x509.packPkcs1(jwk) });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } else if ('pkcs8' === format) {
 | 
					 | 
				
			||||||
    return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) });
 | 
					 | 
				
			||||||
  } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
 | 
					 | 
				
			||||||
    return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) });
 | 
					 | 
				
			||||||
  } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
 | 
					 | 
				
			||||||
    return SSH.pack({ jwk: jwk, comment: opts.comment });
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    throw new Error("Sanity Error: reached unreachable code block with format: " + format);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
RSA.pack = function (opts) {
 | 
					 | 
				
			||||||
  // wrapped in a promise for API compatibility
 | 
					 | 
				
			||||||
  // with the forthcoming browser version
 | 
					 | 
				
			||||||
  // (and potential future native node capability)
 | 
					 | 
				
			||||||
  return Promise.resolve().then(function () {
 | 
					 | 
				
			||||||
    return RSA.exportSync(opts);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
RSA.toPem = RSA.export = RSA.pack;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// snip the _private_ parts... hAHAHAHA!
 | 
					 | 
				
			||||||
var privates = [ 'p', 'q', 'd', 'dp', 'dq', 'qi' ];
 | 
					 | 
				
			||||||
// fix misspelling without breaking the API
 | 
					 | 
				
			||||||
RSA.neuter = RSA.nueter = function (priv) {
 | 
					 | 
				
			||||||
  var pub = {};
 | 
					 | 
				
			||||||
  Object.keys(priv).forEach(function (key) {
 | 
					 | 
				
			||||||
    if (!privates.includes(key)) {
 | 
					 | 
				
			||||||
      pub[key] = priv[key];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  return pub;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RSA.__thumbprint = function (jwk) {
 | 
					 | 
				
			||||||
  var buf = require('crypto').createHash('sha256')
 | 
					 | 
				
			||||||
    // alphabetically sorted keys [ 'e', 'kty', 'n' ]
 | 
					 | 
				
			||||||
    .update('{"e":"' + jwk.e + '","kty":"RSA","n":"' + jwk.n + '"}')
 | 
					 | 
				
			||||||
    .digest()
 | 
					 | 
				
			||||||
  ;
 | 
					 | 
				
			||||||
  return Enc.bufToUrlBase64(buf);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RSA.thumbprint = function (opts) {
 | 
					 | 
				
			||||||
  return Promise.resolve().then(function () {
 | 
					 | 
				
			||||||
    var jwk;
 | 
					 | 
				
			||||||
    if ('RSA' === opts.kty) {
 | 
					 | 
				
			||||||
      jwk = opts;
 | 
					 | 
				
			||||||
    } else if (opts.jwk) {
 | 
					 | 
				
			||||||
      jwk = opts.jwk;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      jwk = RSA.importSync(opts);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return RSA.__thumbprint(jwk);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										111
									
								
								lib/telemetry.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								lib/telemetry.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,111 @@
 | 
				
			|||||||
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// We believe in a proactive approach to sustainable open source.
 | 
				
			||||||
 | 
					// As part of that we make it easy for you to opt-in to following our progress
 | 
				
			||||||
 | 
					// and we also stay up-to-date on telemetry such as operating system and node
 | 
				
			||||||
 | 
					// version so that we can focus our efforts where they'll have the greatest impact.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Want to learn more about our Terms, Privacy Policy, and Mission?
 | 
				
			||||||
 | 
					// Check out https://therootcompany.com/legal/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var os = require('os');
 | 
				
			||||||
 | 
					var crypto = require('crypto');
 | 
				
			||||||
 | 
					var https = require('https');
 | 
				
			||||||
 | 
					var pkg = require('../package.json');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// to help focus our efforts in the right places
 | 
				
			||||||
 | 
					var data = {
 | 
				
			||||||
 | 
					  package: pkg.name
 | 
				
			||||||
 | 
					, version: pkg.version
 | 
				
			||||||
 | 
					, node: process.version
 | 
				
			||||||
 | 
					, arch: process.arch || os.arch()
 | 
				
			||||||
 | 
					, platform: process.platform || os.platform()
 | 
				
			||||||
 | 
					, release: os.release()
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function addCommunityMember(opts) {
 | 
				
			||||||
 | 
					  setTimeout(function () {
 | 
				
			||||||
 | 
					    var req = https.request({
 | 
				
			||||||
 | 
					      hostname: 'api.therootcompany.com'
 | 
				
			||||||
 | 
					    , port: 443
 | 
				
			||||||
 | 
					    , path: '/api/therootcompany.com/public/community'
 | 
				
			||||||
 | 
					    , method: 'POST'
 | 
				
			||||||
 | 
					    , headers: { 'Content-Type': 'application/json' }
 | 
				
			||||||
 | 
					    }, function (resp) {
 | 
				
			||||||
 | 
					      // let the data flow, so we can ignore it
 | 
				
			||||||
 | 
					      resp.on('data', function () {});
 | 
				
			||||||
 | 
					      //resp.on('data', function (chunk) { console.log(chunk.toString()); });
 | 
				
			||||||
 | 
					      resp.on('error', function () { /*ignore*/ });
 | 
				
			||||||
 | 
					      //resp.on('error', function (err) { console.error(err); });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    var obj = JSON.parse(JSON.stringify(data));
 | 
				
			||||||
 | 
					    obj.action = 'updates';
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      obj.ppid = ppid(obj.action);
 | 
				
			||||||
 | 
					    } catch(e) {
 | 
				
			||||||
 | 
					      // ignore
 | 
				
			||||||
 | 
					      //console.error(e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    obj.name = opts.name || undefined;
 | 
				
			||||||
 | 
					    obj.address = opts.email;
 | 
				
			||||||
 | 
					    obj.community = 'node.js@therootcompany.com';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    req.write(JSON.stringify(obj, 2, null));
 | 
				
			||||||
 | 
					    req.end();
 | 
				
			||||||
 | 
					    req.on('error', function () { /*ignore*/ });
 | 
				
			||||||
 | 
					    //req.on('error', function (err) { console.error(err); });
 | 
				
			||||||
 | 
					  }, 50);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function ping(action) {
 | 
				
			||||||
 | 
					  setTimeout(function () {
 | 
				
			||||||
 | 
					    var req = https.request({
 | 
				
			||||||
 | 
					      hostname: 'api.therootcompany.com'
 | 
				
			||||||
 | 
					    , port: 443
 | 
				
			||||||
 | 
					    , path: '/api/therootcompany.com/public/ping'
 | 
				
			||||||
 | 
					    , method: 'POST'
 | 
				
			||||||
 | 
					    , headers: { 'Content-Type': 'application/json' }
 | 
				
			||||||
 | 
					    }, function (resp) {
 | 
				
			||||||
 | 
					      // let the data flow, so we can ignore it
 | 
				
			||||||
 | 
					      resp.on('data', function () { });
 | 
				
			||||||
 | 
					      //resp.on('data', function (chunk) { console.log(chunk.toString()); });
 | 
				
			||||||
 | 
					      resp.on('error', function () { /*ignore*/ });
 | 
				
			||||||
 | 
					      //resp.on('error', function (err) { console.error(err); });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    var obj = JSON.parse(JSON.stringify(data));
 | 
				
			||||||
 | 
					    obj.action = action;
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      obj.ppid = ppid(obj.action);
 | 
				
			||||||
 | 
					    } catch(e) {
 | 
				
			||||||
 | 
					      // ignore
 | 
				
			||||||
 | 
					      //console.error(e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    req.write(JSON.stringify(obj, 2, null));
 | 
				
			||||||
 | 
					    req.end();
 | 
				
			||||||
 | 
					    req.on('error', function (/*e*/) { /*console.error('req.error', e);*/ });
 | 
				
			||||||
 | 
					  }, 50);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// to help identify unique installs without getting
 | 
				
			||||||
 | 
					// the personally identifiable info that we don't want
 | 
				
			||||||
 | 
					function ppid(action) {
 | 
				
			||||||
 | 
					  var parts = [ action, data.package, data.version, data.node, data.arch, data.platform, data.release ];
 | 
				
			||||||
 | 
					  var ifaces = os.networkInterfaces();
 | 
				
			||||||
 | 
					  Object.keys(ifaces).forEach(function (ifname) {
 | 
				
			||||||
 | 
					    if (/^en/.test(ifname) || /^eth/.test(ifname) || /^wl/.test(ifname)) {
 | 
				
			||||||
 | 
					      if  (ifaces[ifname] && ifaces[ifname].length) {
 | 
				
			||||||
 | 
					        parts.push(ifaces[ifname][0].mac);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  return crypto.createHash('sha1').update(parts.join(',')).digest('base64');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports.ping = ping;
 | 
				
			||||||
 | 
					module.exports.joinCommunity = addCommunityMember;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (require.main === module) {
 | 
				
			||||||
 | 
					  ping('install');
 | 
				
			||||||
 | 
					  //addCommunityMember({ name: "AJ ONeal", email: 'coolaj86@gmail.com' });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										41
									
								
								lib/x509.js
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								lib/x509.js
									
									
									
									
									
								
							@ -1,5 +1,7 @@
 | 
				
			|||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO fun idea: create a template from an existing file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var x509 = module.exports;
 | 
					var x509 = module.exports;
 | 
				
			||||||
var ASN1 = require('./asn1.js');
 | 
					var ASN1 = require('./asn1.js');
 | 
				
			||||||
var Enc = require('./encoding.js');
 | 
					var Enc = require('./encoding.js');
 | 
				
			||||||
@ -112,42 +114,3 @@ x509.packPkcs1 = function (jwk) {
 | 
				
			|||||||
  , ASN1.UInt(Enc.base64ToHex(jwk.qi))
 | 
					  , ASN1.UInt(Enc.base64ToHex(jwk.qi))
 | 
				
			||||||
  ));
 | 
					  ));
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
x509.packPkcs8 = function (jwk) {
 | 
					 | 
				
			||||||
  if (!jwk.d) {
 | 
					 | 
				
			||||||
    // Public RSA
 | 
					 | 
				
			||||||
    return Enc.hexToBuf(ASN1('30'
 | 
					 | 
				
			||||||
      , ASN1('30'
 | 
					 | 
				
			||||||
        , ASN1('06', '2a864886f70d010101')
 | 
					 | 
				
			||||||
        , ASN1('05')
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      , ASN1.BitStr(ASN1('30'
 | 
					 | 
				
			||||||
        , ASN1.UInt(Enc.base64ToHex(jwk.n))
 | 
					 | 
				
			||||||
        , ASN1.UInt(Enc.base64ToHex(jwk.e))
 | 
					 | 
				
			||||||
      ))
 | 
					 | 
				
			||||||
    ));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Private RSA
 | 
					 | 
				
			||||||
  return Enc.hexToBuf(ASN1('30'
 | 
					 | 
				
			||||||
    , ASN1.UInt('00')
 | 
					 | 
				
			||||||
    , ASN1('30'
 | 
					 | 
				
			||||||
      , ASN1('06', '2a864886f70d010101')
 | 
					 | 
				
			||||||
      , ASN1('05')
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    , ASN1('04'
 | 
					 | 
				
			||||||
      , ASN1('30'
 | 
					 | 
				
			||||||
        , ASN1.UInt('00')
 | 
					 | 
				
			||||||
        , ASN1.UInt(Enc.base64ToHex(jwk.n))
 | 
					 | 
				
			||||||
        , ASN1.UInt(Enc.base64ToHex(jwk.e))
 | 
					 | 
				
			||||||
        , ASN1.UInt(Enc.base64ToHex(jwk.d))
 | 
					 | 
				
			||||||
        , ASN1.UInt(Enc.base64ToHex(jwk.p))
 | 
					 | 
				
			||||||
        , ASN1.UInt(Enc.base64ToHex(jwk.q))
 | 
					 | 
				
			||||||
        , ASN1.UInt(Enc.base64ToHex(jwk.dp))
 | 
					 | 
				
			||||||
        , ASN1.UInt(Enc.base64ToHex(jwk.dq))
 | 
					 | 
				
			||||||
        , ASN1.UInt(Enc.base64ToHex(jwk.qi))
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  ));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
x509.packSpki = x509.packPkcs8;
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										20
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								package.json
									
									
									
									
									
								
							@ -1,7 +1,7 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "rasha",
 | 
					  "name": "rasha",
 | 
				
			||||||
  "version": "1.3.0",
 | 
					  "version": "0.8.2",
 | 
				
			||||||
  "description": "💯 PEM-to-JWK and JWK-to-PEM for RSA keys in a lightweight, zero-dependency library focused on perfect universal compatibility.",
 | 
					  "description": "PEM-to-JWK and JWK-to-PEM for RSA keys in a lightweight, zero-dependency library focused on perfect universal compatibility.",
 | 
				
			||||||
  "homepage": "https://git.coolaj86.com/coolaj86/rasha.js",
 | 
					  "homepage": "https://git.coolaj86.com/coolaj86/rasha.js",
 | 
				
			||||||
  "main": "index.js",
 | 
					  "main": "index.js",
 | 
				
			||||||
  "bin": {
 | 
					  "bin": {
 | 
				
			||||||
@ -16,7 +16,8 @@
 | 
				
			|||||||
    "lib": "lib"
 | 
					    "lib": "lib"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "test": "bash test.sh"
 | 
					    "postinstall": "node lib/telemetry.js event:install",
 | 
				
			||||||
 | 
					    "test": "echo \"Error: no test specified\" && exit 1"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
    "type": "git",
 | 
					    "type": "git",
 | 
				
			||||||
@ -25,18 +26,15 @@
 | 
				
			|||||||
  "keywords": [
 | 
					  "keywords": [
 | 
				
			||||||
    "zero-dependency",
 | 
					    "zero-dependency",
 | 
				
			||||||
    "PEM-to-JWK",
 | 
					    "PEM-to-JWK",
 | 
				
			||||||
    "JWK-to-PEM",
 | 
					 | 
				
			||||||
    "RSA",
 | 
					    "RSA",
 | 
				
			||||||
    "2048",
 | 
					    "2048",
 | 
				
			||||||
    "4096",
 | 
					    "4096",
 | 
				
			||||||
    "asn1",
 | 
					    "asn1",
 | 
				
			||||||
    "x509",
 | 
					    "x509"
 | 
				
			||||||
    "JWK-to-SSH",
 | 
					  ],
 | 
				
			||||||
    "PEM-to-SSH"
 | 
					  "xkeywords": [
 | 
				
			||||||
 | 
					    "JWK-to-PEM"
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
 | 
					  "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
 | 
				
			||||||
  "license": "MPL-2.0",
 | 
					  "license": "MPL-2.0"
 | 
				
			||||||
  "trulyOptionalDependencies": {
 | 
					 | 
				
			||||||
    "node-forge": "^0.8.2"
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										218
									
								
								test.sh
									
									
									
									
									
								
							
							
						
						
									
										218
									
								
								test.sh
									
									
									
									
									
								
							@ -1,186 +1,70 @@
 | 
				
			|||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					 | 
				
			||||||
# cause errors to hard-fail
 | 
					 | 
				
			||||||
# (and diff non-0 exit status will cause failure)
 | 
					 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pemtojwk() {
 | 
					 | 
				
			||||||
	keyid=$1
 | 
					 | 
				
			||||||
  if [ -z "$keyid" ]; then
 | 
					 | 
				
			||||||
    echo ""
 | 
					 | 
				
			||||||
    echo "Testing PEM-to-JWK PKCS#1"
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/privkey-rsa-2048.pkcs1.${keyid}pem \
 | 
					 | 
				
			||||||
    > ./fixtures/privkey-rsa-2048.jwk.1.json
 | 
					 | 
				
			||||||
	diff ./fixtures/privkey-rsa-2048.jwk.${keyid}json ./fixtures/privkey-rsa-2048.jwk.1.json
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/pub-rsa-2048.pkcs1.${keyid}pem \
 | 
					 | 
				
			||||||
    > ./fixtures/pub-rsa-2048.jwk.1.json
 | 
					 | 
				
			||||||
	diff ./fixtures/pub-rsa-2048.jwk.${keyid}json ./fixtures/pub-rsa-2048.jwk.1.json
 | 
					 | 
				
			||||||
  if [ -z "$keyid" ]; then
 | 
					 | 
				
			||||||
    echo "Pass"
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if [ -z "$keyid" ]; then
 | 
					 | 
				
			||||||
    echo ""
 | 
					 | 
				
			||||||
    echo "Testing PEM-to-JWK PKCS#8"
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/privkey-rsa-2048.pkcs8.${keyid}pem \
 | 
					 | 
				
			||||||
    > ./fixtures/privkey-rsa-2048.jwk.1.json
 | 
					 | 
				
			||||||
	diff ./fixtures/privkey-rsa-2048.jwk.${keyid}json ./fixtures/privkey-rsa-2048.jwk.1.json
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/pub-rsa-2048.spki.${keyid}pem \
 | 
					 | 
				
			||||||
    > ./fixtures/pub-rsa-2048.jwk.1.json
 | 
					 | 
				
			||||||
	diff ./fixtures/pub-rsa-2048.jwk.${keyid}json ./fixtures/pub-rsa-2048.jwk.1.json
 | 
					 | 
				
			||||||
  if [ -z "$keyid" ]; then
 | 
					 | 
				
			||||||
    echo "Pass"
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jwktopem() {
 | 
					 | 
				
			||||||
	keyid=$1
 | 
					 | 
				
			||||||
  if [ -z "$keyid" ]; then
 | 
					 | 
				
			||||||
    echo ""
 | 
					 | 
				
			||||||
    echo "Testing JWK-to-PEM PKCS#1"
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/privkey-rsa-2048.jwk.${keyid}json pkcs1 \
 | 
					 | 
				
			||||||
    > ./fixtures/privkey-rsa-2048.pkcs1.1.pem
 | 
					 | 
				
			||||||
	diff ./fixtures/privkey-rsa-2048.pkcs1.${keyid}pem ./fixtures/privkey-rsa-2048.pkcs1.1.pem
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/pub-rsa-2048.jwk.${keyid}json pkcs1 \
 | 
					 | 
				
			||||||
    > ./fixtures/pub-rsa-2048.pkcs1.1.pem
 | 
					 | 
				
			||||||
	diff ./fixtures/pub-rsa-2048.pkcs1.${keyid}pem ./fixtures/pub-rsa-2048.pkcs1.1.pem
 | 
					 | 
				
			||||||
  if [ -z "$keyid" ]; then
 | 
					 | 
				
			||||||
    echo "Pass"
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if [ -z "$keyid" ]; then
 | 
					 | 
				
			||||||
    echo ""
 | 
					 | 
				
			||||||
    echo "Testing JWK-to-PEM PKCS#8"
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/privkey-rsa-2048.jwk.${keyid}json pkcs8 \
 | 
					 | 
				
			||||||
    > ./fixtures/privkey-rsa-2048.pkcs8.1.pem
 | 
					 | 
				
			||||||
	diff ./fixtures/privkey-rsa-2048.pkcs8.${keyid}pem ./fixtures/privkey-rsa-2048.pkcs8.1.pem
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/pub-rsa-2048.jwk.${keyid}json spki \
 | 
					 | 
				
			||||||
    > ./fixtures/pub-rsa-2048.spki.1.pem
 | 
					 | 
				
			||||||
	diff ./fixtures/pub-rsa-2048.spki.${keyid}pem ./fixtures/pub-rsa-2048.spki.1.pem
 | 
					 | 
				
			||||||
  if [ -z "$keyid" ]; then
 | 
					 | 
				
			||||||
    echo "Pass"
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if [ -z "$keyid" ]; then
 | 
					 | 
				
			||||||
    echo ""
 | 
					 | 
				
			||||||
    echo "Testing JWK-to-SSH"
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/privkey-rsa-2048.jwk.${keyid}json ssh > ./fixtures/pub-rsa-2048.ssh.1.pub
 | 
					 | 
				
			||||||
	diff ./fixtures/pub-rsa-2048.ssh.${keyid}pub ./fixtures/pub-rsa-2048.ssh.1.pub
 | 
					 | 
				
			||||||
	#
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/pub-rsa-2048.jwk.${keyid}json ssh > ./fixtures/pub-rsa-2048.ssh.1.pub
 | 
					 | 
				
			||||||
	diff ./fixtures/pub-rsa-2048.ssh.${keyid}pub ./fixtures/pub-rsa-2048.ssh.1.pub
 | 
					 | 
				
			||||||
  if [ -z "$keyid" ]; then
 | 
					 | 
				
			||||||
    echo "Pass"
 | 
					 | 
				
			||||||
  fi
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
rndkey() {
 | 
					 | 
				
			||||||
	keyid="rnd.1."
 | 
					 | 
				
			||||||
  keysize=$1
 | 
					 | 
				
			||||||
	# Generate 2048-bit RSA Keypair
 | 
					 | 
				
			||||||
	openssl genrsa -out fixtures/privkey-rsa-2048.pkcs1.${keyid}pem $keysize
 | 
					 | 
				
			||||||
	# Convert PKCS1 (traditional) RSA Keypair to PKCS8 format
 | 
					 | 
				
			||||||
	openssl rsa -in fixtures/privkey-rsa-2048.pkcs1.${keyid}pem -pubout \
 | 
					 | 
				
			||||||
    -out fixtures/pub-rsa-2048.spki.${keyid}pem
 | 
					 | 
				
			||||||
	# Export Public-only RSA Key in PKCS1 (traditional) format
 | 
					 | 
				
			||||||
	openssl pkcs8 -topk8 -nocrypt -in fixtures/privkey-rsa-2048.pkcs1.${keyid}pem \
 | 
					 | 
				
			||||||
    -out fixtures/privkey-rsa-2048.pkcs8.${keyid}pem
 | 
					 | 
				
			||||||
	# Convert PKCS1 (traditional) RSA Public Key to SPKI/PKIX format
 | 
					 | 
				
			||||||
	openssl rsa -in fixtures/pub-rsa-2048.spki.${keyid}pem -pubin -RSAPublicKey_out \
 | 
					 | 
				
			||||||
    -out fixtures/pub-rsa-2048.pkcs1.${keyid}pem
 | 
					 | 
				
			||||||
	# Convert RSA public key to SSH format
 | 
					 | 
				
			||||||
  sshpub=$(ssh-keygen -f fixtures/pub-rsa-2048.spki.${keyid}pem -i -mPKCS8)
 | 
					 | 
				
			||||||
  echo "$sshpub rsa@localhost" > fixtures/pub-rsa-2048.ssh.${keyid}pub
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  # to JWK
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/privkey-rsa-2048.pkcs1.${keyid}pem \
 | 
					 | 
				
			||||||
    > ./fixtures/privkey-rsa-2048.jwk.${keyid}json
 | 
					 | 
				
			||||||
	node bin/rasha.js ./fixtures/pub-rsa-2048.pkcs1.${keyid}pem \
 | 
					 | 
				
			||||||
    > ./fixtures/pub-rsa-2048.jwk.${keyid}json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pemtojwk "$keyid"
 | 
					 | 
				
			||||||
  jwktopem "$keyid"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pemtojwk ""
 | 
					 | 
				
			||||||
jwktopem ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo ""
 | 
					echo ""
 | 
				
			||||||
echo "testing node key generation"
 | 
					echo ""
 | 
				
			||||||
echo "defaults"
 | 
					echo "Testing PEM-to-JWK PKCS#1"
 | 
				
			||||||
node bin/rasha.js > /dev/null
 | 
					echo ""
 | 
				
			||||||
echo "jwk"
 | 
					#
 | 
				
			||||||
node bin/rasha.js jwk > /dev/null
 | 
					node bin/rasha.js ./fixtures/privkey-rsa-2048.pkcs1.pem > ./fixtures/privkey-rsa-2048.jwk.1.json
 | 
				
			||||||
echo "json 2048"
 | 
					diff ./fixtures/privkey-rsa-2048.jwk.json ./fixtures/privkey-rsa-2048.jwk.1.json
 | 
				
			||||||
node bin/rasha.js json 2048 > /dev/null
 | 
					#
 | 
				
			||||||
echo "der"
 | 
					node bin/rasha.js ./fixtures/pub-rsa-2048.pkcs1.pem > ./fixtures/pub-rsa-2048.jwk.1.json
 | 
				
			||||||
node bin/rasha.js der > /dev/null
 | 
					diff ./fixtures/pub-rsa-2048.jwk.json ./fixtures/pub-rsa-2048.jwk.1.json
 | 
				
			||||||
echo "pkcs8 der"
 | 
					
 | 
				
			||||||
node bin/rasha.js pkcs8 der > /dev/null
 | 
					 | 
				
			||||||
echo "pem"
 | 
					 | 
				
			||||||
node bin/rasha.js pem > /dev/null
 | 
					 | 
				
			||||||
echo "pkcs1"
 | 
					 | 
				
			||||||
node bin/rasha.js pkcs1 pem > /dev/null
 | 
					 | 
				
			||||||
echo "spki"
 | 
					 | 
				
			||||||
node bin/rasha.js spki > /dev/null
 | 
					 | 
				
			||||||
echo "PASS"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo ""
 | 
					echo ""
 | 
				
			||||||
echo ""
 | 
					echo ""
 | 
				
			||||||
echo "Re-running tests with random keys of varying sizes"
 | 
					echo "Testing PEM-to-JWK PKCS#8"
 | 
				
			||||||
echo ""
 | 
					echo ""
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					node bin/rasha.js ./fixtures/privkey-rsa-2048.pkcs8.pem > ./fixtures/privkey-rsa-2048.jwk.1.json
 | 
				
			||||||
 | 
					diff ./fixtures/privkey-rsa-2048.jwk.json ./fixtures/privkey-rsa-2048.jwk.1.json
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					node bin/rasha.js ./fixtures/pub-rsa-2048.spki.pem > ./fixtures/pub-rsa-2048.jwk.1.json
 | 
				
			||||||
 | 
					diff ./fixtures/pub-rsa-2048.jwk.json ./fixtures/pub-rsa-2048.jwk.1.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# commented out sizes below 512, since they are below minimum size on some systems.
 | 
					 | 
				
			||||||
# rndkey 32 # minimum key size
 | 
					 | 
				
			||||||
# rndkey 64
 | 
					 | 
				
			||||||
# rndkey 128
 | 
					 | 
				
			||||||
# rndkey 256
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
rndkey 512
 | 
					 | 
				
			||||||
rndkey 768
 | 
					 | 
				
			||||||
rndkey 1024
 | 
					 | 
				
			||||||
rndkey 2048 # first secure key size
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if [ "${RASHA_TEST_LARGE_KEYS}" == "true" ]; then
 | 
					 | 
				
			||||||
  rndkey 3072
 | 
					 | 
				
			||||||
  rndkey 4096 # largest reasonable key size
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
  echo ""
 | 
					 | 
				
			||||||
  echo "Note:"
 | 
					 | 
				
			||||||
  echo "Keys larger than 2048 have been tested and work, but are omitted from automated tests to save time."
 | 
					 | 
				
			||||||
  echo "Set RASHA_TEST_LARGE_KEYS=true to enable testing of keys up to 4096."
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo ""
 | 
					echo ""
 | 
				
			||||||
echo "Pass"
 | 
					echo ""
 | 
				
			||||||
 | 
					echo "Testing JWK-to-PEM PKCS#1"
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					node bin/rasha.js ./fixtures/privkey-rsa-2048.jwk.json pkcs1 > ./fixtures/privkey-rsa-2048.pkcs1.1.pem
 | 
				
			||||||
 | 
					diff ./fixtures/privkey-rsa-2048.pkcs1.pem ./fixtures/privkey-rsa-2048.pkcs1.1.pem
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					node bin/rasha.js ./fixtures/pub-rsa-2048.jwk.json pkcs1 > ./fixtures/pub-rsa-2048.pkcs1.1.pem
 | 
				
			||||||
 | 
					diff ./fixtures/pub-rsa-2048.pkcs1.pem ./fixtures/pub-rsa-2048.pkcs1.1.pem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#echo ""
 | 
				
			||||||
 | 
					#echo ""
 | 
				
			||||||
 | 
					#echo "Testing JWK-to-PEM PKCS#8"
 | 
				
			||||||
 | 
					#echo ""
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#node bin/rasha.js ./fixtures/privkey-rsa-2048.jwk.json pkcs8 > ./fixtures/privkey-rsa-2048.pkcs8.1.pem
 | 
				
			||||||
 | 
					#diff ./fixtures/privkey-rsa-2048.pkcs8.pem ./fixtures/privkey-rsa-2048.pkcs8.1.pem
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#node bin/rasha.js ./fixtures/pub-rsa-2048.jwk.json spki > ./fixtures/pub-rsa-2048.spki.1.pem
 | 
				
			||||||
 | 
					#diff ./fixtures/pub-rsa-2048.pski.pem ./fixtures/pub-rsa-2048.spki.1.pem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
 | 
					echo "Testing JWK-to-SSH"
 | 
				
			||||||
 | 
					echo ""
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					node bin/rasha.js ./fixtures/privkey-rsa-2048.jwk.json ssh > ./fixtures/pub-rsa-2048.ssh.1.pub
 | 
				
			||||||
 | 
					diff ./fixtures/pub-rsa-2048.ssh.pub ./fixtures/pub-rsa-2048.ssh.1.pub
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					node bin/rasha.js ./fixtures/pub-rsa-2048.jwk.json ssh > ./fixtures/pub-rsa-2048.ssh.1.pub
 | 
				
			||||||
 | 
					diff ./fixtures/pub-rsa-2048.ssh.pub ./fixtures/pub-rsa-2048.ssh.1.pub
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rm fixtures/*.1.*
 | 
					rm fixtures/*.1.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo ""
 | 
					 | 
				
			||||||
echo "Testing Thumbprints"
 | 
					 | 
				
			||||||
node bin/rasha.js ./fixtures/privkey-rsa-2048.pkcs1.pem thumbprint
 | 
					 | 
				
			||||||
node bin/rasha.js ./fixtures/pub-rsa-2048.jwk.json thumbprint
 | 
					 | 
				
			||||||
echo "PASS"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
echo ""
 | 
					echo ""
 | 
				
			||||||
echo ""
 | 
					echo ""
 | 
				
			||||||
echo "PASSED:"
 | 
					echo "PASSED:"
 | 
				
			||||||
echo "• All inputs produced valid outputs"
 | 
					echo "• All inputs produced valid outputs"
 | 
				
			||||||
echo "• All outputs matched known-good values"
 | 
					echo "• All outputs matched known-good values"
 | 
				
			||||||
echo "• All random tests passed reciprosity"
 | 
					echo ""
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user