v1.0.0: parses bytes, packs type and bytes
This commit is contained in:
parent
e2d048cacf
commit
72d95531d3
|
@ -1,3 +1,5 @@
|
||||||
|
*.gz
|
||||||
|
|
||||||
# ---> Node
|
# ---> Node
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"printWidth": 80,
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 4,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"useTabs": true
|
||||||
|
}
|
123
README.md
123
README.md
|
@ -1,3 +1,122 @@
|
||||||
# pem.js
|
# @root/pem
|
||||||
|
|
||||||
Lightweight, Zero-Dependency, PEM (RFC 7468) encoder and decoder.
|
Lightweight, Zero-Dependency PEM encoder and decoder.
|
||||||
|
|
||||||
|
| ~300b gzipped
|
||||||
|
| ~650b minified
|
||||||
|
| ~1k full
|
||||||
|
|
|
||||||
|
|
||||||
|
- [x] VanillaJS
|
||||||
|
- [x] Zero-Dependency
|
||||||
|
- [x] Universal Support
|
||||||
|
- [x] Node.js
|
||||||
|
- [x] Browsers
|
||||||
|
|
||||||
|
# Support
|
||||||
|
|
||||||
|
This library supports PEM, which is pretty boring on its own.
|
||||||
|
|
||||||
|
Most likely you are also interested in some of the following:
|
||||||
|
|
||||||
|
- [keypairs.js](https://git.rootprojects.org/root/keypairs.js)
|
||||||
|
- RSA
|
||||||
|
- EC / ECDSA
|
||||||
|
- [x509.js](https://git.rootprojects.org/root/x509.js)
|
||||||
|
- [asn1.js](https://git.rootprojects.org/root/asn1.js)
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
- PEM.parseBlock(str)
|
||||||
|
- PEM.packBlock(options)
|
||||||
|
|
||||||
|
Parsing
|
||||||
|
|
||||||
|
```js
|
||||||
|
var PEM = require('@root/pem/parser');
|
||||||
|
|
||||||
|
var block = PEM.parseBlock(
|
||||||
|
'-----BEGIN Type-----\nSGVsbG8sIOS4lueVjCE=\n-----END Type-----\n'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
bytes: `<48 65 6c 6c 6f 2c 20 e4 b8 96 e7 95 8c 21>`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Packing
|
||||||
|
|
||||||
|
```js
|
||||||
|
var PEM = require('@root/pem/packer');
|
||||||
|
|
||||||
|
var block = PEM.packBlock({
|
||||||
|
type: 'Type',
|
||||||
|
// Buffer or Uint8Array or Array
|
||||||
|
bytes: [0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c, 0x21]
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
```txt
|
||||||
|
-----BEGIN Type-----
|
||||||
|
SGVsbG8sIOS4lueVjCE=
|
||||||
|
-----END Type-----
|
||||||
|
```
|
||||||
|
|
||||||
|
# Install
|
||||||
|
|
||||||
|
## Node / Webpack
|
||||||
|
|
||||||
|
```js
|
||||||
|
npm install -g @root/pem
|
||||||
|
```
|
||||||
|
|
||||||
|
## Browsers
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script src="https://unpkg.com/@root/pem/dist/pem.all.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script src="https://unpkg.com/@root/pem/dist/pem.all.min.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
# A PEM Block
|
||||||
|
|
||||||
|
A Block represents a PEM encoded structure.
|
||||||
|
|
||||||
|
The encoded form is:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
-----BEGIN Type-----
|
||||||
|
Headers
|
||||||
|
base64-encoded Bytes
|
||||||
|
-----END Type-----
|
||||||
|
```
|
||||||
|
|
||||||
|
where Headers is a possibly empty sequence of Key: Value lines.
|
||||||
|
|
||||||
|
(credit: https://golang.org/pkg/encoding/pem/)
|
||||||
|
|
||||||
|
# PEM History
|
||||||
|
|
||||||
|
PEM was introduced in 1993 via RFC 1421, but not formally
|
||||||
|
standardized until RFC 7468 in April of 2015.
|
||||||
|
|
||||||
|
It has served as the _de facto_ standard for a variety of
|
||||||
|
DER-encoded X509 schemas of ASN.1 data for cryptographic
|
||||||
|
keys and certificates such as:
|
||||||
|
|
||||||
|
- [x] PKCS#10 (Certificate Signing Request [CSR])
|
||||||
|
- [x] X509 Certificate (fullchain.pem, site.crt)
|
||||||
|
- [x] PKIX (cert.pem, privkey.pem, priv.key)
|
||||||
|
- [x] PKCS#1 (RSA Public and Private Keys)
|
||||||
|
- [x] PKCS#8 (RSA and ECDSA Keypairs)
|
||||||
|
- [x] SEC#1 (ECDSARSA Public and Private Keys)
|
||||||
|
|
||||||
|
# Legal
|
||||||
|
|
||||||
|
MPL-2.0 |
|
||||||
|
[Terms of Use](https://therootcompany.com/legal/#terms) |
|
||||||
|
[Privacy Policy](https://therootcompany.com/legal/#privacy)
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// "A little copying is better than a little dependency" - Rob Pike
|
||||||
|
var Enc = module.exports;
|
||||||
|
|
||||||
|
Enc.bufToBase64 = function(u8) {
|
||||||
|
var bin = '';
|
||||||
|
// map is not part of u8
|
||||||
|
u8.forEach(function(i) {
|
||||||
|
bin += String.fromCharCode(i);
|
||||||
|
});
|
||||||
|
return btoa(bin);
|
||||||
|
};
|
||||||
|
|
||||||
|
Enc.base64ToBuf = function(b64) {
|
||||||
|
return Uint8Array.from(
|
||||||
|
atob(b64)
|
||||||
|
.split('')
|
||||||
|
.map(function(ch) {
|
||||||
|
return ch.charCodeAt(0);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,33 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Enc = require('@root/encoding/base64');
|
||||||
|
var PEM = module.exports;
|
||||||
|
|
||||||
|
PEM.packBlock = function(opts) {
|
||||||
|
// TODO allow for headers?
|
||||||
|
return (
|
||||||
|
'-----BEGIN ' +
|
||||||
|
opts.type +
|
||||||
|
'-----\n' +
|
||||||
|
Enc.bufToBase64(opts.bytes)
|
||||||
|
.match(/.{1,64}/g)
|
||||||
|
.join('\n') +
|
||||||
|
'\n' +
|
||||||
|
'-----END ' +
|
||||||
|
opts.type +
|
||||||
|
'-----'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// don't replace the full parseBlock, if it exists
|
||||||
|
PEM.parseBlock =
|
||||||
|
PEM.parseBlock ||
|
||||||
|
function(str) {
|
||||||
|
var der = str
|
||||||
|
.split(/\n/)
|
||||||
|
.filter(function(line) {
|
||||||
|
return !/-----/.test(line);
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
return { bytes: Enc.base64ToBuf(der) };
|
||||||
|
};
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# TODO convert to JS
|
||||||
|
cat browser/native.js parser.js packer.js > all.tmp.js
|
||||||
|
sed -i '' '/use strict/d' all.tmp.js
|
||||||
|
sed -i '' '/require/d' all.tmp.js
|
||||||
|
sed -i '' '/exports/d' all.tmp.js
|
||||||
|
echo ';(function () {' > all.js
|
||||||
|
echo "'use strict';" >> all.js
|
||||||
|
echo "var PEM = window.PEM = {};" >> all.js
|
||||||
|
echo "var Enc = {};" >> all.js
|
||||||
|
cat all.tmp.js >> all.js
|
||||||
|
rm all.tmp.js
|
||||||
|
echo '}());' >> all.js
|
||||||
|
|
||||||
|
mv all.js dist/pem.all.js
|
||||||
|
uglifyjs dist/pem.all.js > dist/pem.all.min.js
|
|
@ -0,0 +1,56 @@
|
||||||
|
;(function () {
|
||||||
|
'use strict';
|
||||||
|
var PEM = window.PEM = {};
|
||||||
|
var Enc = {};
|
||||||
|
|
||||||
|
// "A little copying is better than a little dependency" - Rob Pike
|
||||||
|
|
||||||
|
Enc.bufToBase64 = function(u8) {
|
||||||
|
var bin = '';
|
||||||
|
// map is not part of u8
|
||||||
|
u8.forEach(function(i) {
|
||||||
|
bin += String.fromCharCode(i);
|
||||||
|
});
|
||||||
|
return btoa(bin);
|
||||||
|
};
|
||||||
|
|
||||||
|
Enc.base64ToBuf = function(b64) {
|
||||||
|
return Uint8Array.from(
|
||||||
|
atob(b64)
|
||||||
|
.split('')
|
||||||
|
.map(function(ch) {
|
||||||
|
return ch.charCodeAt(0);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PEM.parseBlock = function(str) {
|
||||||
|
var der = str
|
||||||
|
.split(/\n/)
|
||||||
|
.filter(function(line) {
|
||||||
|
return !/-----/.test(line);
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
return { bytes: Enc.base64ToBuf(der) };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PEM.packBlock = function(opts) {
|
||||||
|
// TODO allow for headers?
|
||||||
|
return (
|
||||||
|
'-----BEGIN ' +
|
||||||
|
opts.type +
|
||||||
|
'-----\n' +
|
||||||
|
Enc.bufToBase64(opts.bytes)
|
||||||
|
.match(/.{1,64}/g)
|
||||||
|
.join('\n') +
|
||||||
|
'\n' +
|
||||||
|
'-----END ' +
|
||||||
|
opts.type +
|
||||||
|
'-----'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}());
|
|
@ -0,0 +1 @@
|
||||||
|
(function(){"use strict";var PEM=window.PEM={};var Enc={};Enc.bufToBase64=function(u8){var bin="";u8.forEach(function(i){bin+=String.fromCharCode(i)});return btoa(bin)};Enc.base64ToBuf=function(b64){return Uint8Array.from(atob(b64).split("").map(function(ch){return ch.charCodeAt(0)}))};PEM.parseBlock=function(str){var der=str.split(/\n/).filter(function(line){return!/-----/.test(line)}).join("");return{bytes:Enc.base64ToBuf(der)}};PEM.packBlock=function(opts){return"-----BEGIN "+opts.type+"-----\n"+Enc.bufToBase64(opts.bytes).match(/.{1,64}/g).join("\n")+"\n"+"-----END "+opts.type+"-----"}})();
|
|
@ -0,0 +1,7 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var PEM = require('./parser.js');
|
||||||
|
var PEMPacker = require('./packer.js');
|
||||||
|
PEM.packBlock = PEMPacker.packBlock;
|
||||||
|
|
||||||
|
module.exports = PEM;
|
|
@ -0,0 +1,12 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// "A little copying is better than a little dependency" - Rob Pike
|
||||||
|
var Enc = module.exports;
|
||||||
|
|
||||||
|
Enc.bufToBase64 = function(buf) {
|
||||||
|
return Buffer.from(buf).toString('base64');
|
||||||
|
};
|
||||||
|
|
||||||
|
Enc.base64ToBuf = function(b64) {
|
||||||
|
return Buffer.from(b64, 'base64');
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "@root/pem",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "VanillaJS, Lightweight, Zero-Dependency, PEM encoder and decoder.",
|
||||||
|
"main": "index.js",
|
||||||
|
"browser": {
|
||||||
|
"./node/native.js": "./browser/native.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "node tests"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.rootprojects.org/root/pem.js.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"PEM",
|
||||||
|
"x509",
|
||||||
|
"ASN.1",
|
||||||
|
"asn1",
|
||||||
|
"RFC7468",
|
||||||
|
"RFC1421",
|
||||||
|
"RFC",
|
||||||
|
"7468",
|
||||||
|
"1421"
|
||||||
|
],
|
||||||
|
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
||||||
|
"license": "MPL-2.0"
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var PEM = module.exports;
|
||||||
|
|
||||||
|
//var Enc = require('@root/encoding/base64');
|
||||||
|
var Enc = require('./node/native.js');
|
||||||
|
|
||||||
|
PEM.packBlock = function(opts) {
|
||||||
|
// TODO allow for headers?
|
||||||
|
return (
|
||||||
|
'-----BEGIN ' +
|
||||||
|
opts.type +
|
||||||
|
'-----\n' +
|
||||||
|
Enc.bufToBase64(opts.bytes)
|
||||||
|
.match(/.{1,64}/g)
|
||||||
|
.join('\n') +
|
||||||
|
'\n' +
|
||||||
|
'-----END ' +
|
||||||
|
opts.type +
|
||||||
|
'-----'
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,15 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var PEM = module.exports;
|
||||||
|
|
||||||
|
var Enc = require('./node/native.js');
|
||||||
|
|
||||||
|
PEM.parseBlock = function(str) {
|
||||||
|
var der = str
|
||||||
|
.split(/\n/)
|
||||||
|
.filter(function(line) {
|
||||||
|
return !/-----/.test(line);
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
return { bytes: Enc.base64ToBuf(der) };
|
||||||
|
};
|
|
@ -0,0 +1,36 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var PEM = require('../');
|
||||||
|
//console.log(PEM);
|
||||||
|
|
||||||
|
// "Hello, 世界!";
|
||||||
|
var contents = 'SGVs\nbG8sIOS4\nlueVjCE=';
|
||||||
|
var pem = '-----BEGIN Type-----\n' + contents + '\n-----END Type-----\n';
|
||||||
|
var block = PEM.parseBlock(pem);
|
||||||
|
|
||||||
|
if (14 !== block.bytes.byteLength) {
|
||||||
|
throw new Error('should be 14 bytes');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0x48 !== block.bytes[0]) {
|
||||||
|
throw new Error('first byte should be 0x48 ("H")');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0x8c !== block.bytes[12]) {
|
||||||
|
throw new Error('13th byte should be 0x8c (3rd byte of "界")');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info("PASS: decodes 'bytes' field correctly");
|
||||||
|
|
||||||
|
var pem2 =
|
||||||
|
'-----BEGIN Type-----\n' +
|
||||||
|
contents.replace(/\n/g, '') +
|
||||||
|
'\n-----END Type-----';
|
||||||
|
|
||||||
|
block.type = 'Type';
|
||||||
|
if (pem2 !== PEM.packBlock(block)) {
|
||||||
|
console.debug(PEM.packBlock(block));
|
||||||
|
throw new Error('should pack PEM correctly');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.info("PASS: encodes 'bytes' and 'type' fields correctly");
|
Loading…
Reference in New Issue