v1.0.0: parses bytes, packs type and bytes
This commit is contained in:
parent
e2d048cacf
commit
72d95531d3
|
@ -1,3 +1,5 @@
|
|||
*.gz
|
||||
|
||||
# ---> Node
|
||||
# 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