101 lines
3.3 KiB
TypeScript
101 lines
3.3 KiB
TypeScript
|
interface Header {
|
||
|
name: string;
|
||
|
offset: number;
|
||
|
length: number;
|
||
|
derived?: boolean
|
||
|
}
|
||
|
|
||
|
export const Constants = {
|
||
|
crypto:
|
||
|
{
|
||
|
RAW_KEY_LENGTH: 32,
|
||
|
SIGN_PRIVATE_KEY_HEADER: Buffer.from("302e020100300506032b657004220420", "hex"),
|
||
|
ENCRYPT_PRIVATE_KEY_HEADER: Buffer.from("302e020100300506032b656e04220420", "hex"),
|
||
|
PRIVATE_KEY_LENGTH: 48,
|
||
|
SIGN_PUBLIC_KEY_HEADER: Buffer.from("302a300506032b6570032100", "hex"),
|
||
|
ENCRYPT_PUBLIC_KEY_HEADER: Buffer.from("302a300506032b656e032100", "hex"),
|
||
|
PUBLIC_KEY_LENGTH: 44,
|
||
|
SIGNATURE_LENGTH: 64
|
||
|
},
|
||
|
fields: {
|
||
|
PAYLOAD_LENGTH_OFFSET: -1, // filled in below
|
||
|
TOTAL_HEADERS_LENGTH: -1,
|
||
|
PAYLOAD_MAX_LENGTH: -1, // 64KB - headers
|
||
|
headers: [
|
||
|
{
|
||
|
name: "MAGIC",
|
||
|
offset: 0,
|
||
|
length: 2
|
||
|
},
|
||
|
{
|
||
|
name: "PROTOCOL_VERSION",
|
||
|
offset: 2,
|
||
|
length: 1
|
||
|
},
|
||
|
{
|
||
|
name: "SIGNATURE_VERSION",
|
||
|
offset: 3,
|
||
|
length: 1
|
||
|
},
|
||
|
{
|
||
|
name: "TIMESTAMP",
|
||
|
offset: 4,
|
||
|
length: 4,
|
||
|
"derived": true
|
||
|
},
|
||
|
{
|
||
|
name: "MESSAGE_ID",
|
||
|
offset: 8,
|
||
|
length: 4
|
||
|
},
|
||
|
{
|
||
|
name: "PAYLOAD_TYPE",
|
||
|
offset: 12,
|
||
|
length: 1
|
||
|
},
|
||
|
{
|
||
|
name: "RESERVED",
|
||
|
offset: 13,
|
||
|
length: 1
|
||
|
},
|
||
|
{
|
||
|
name: "PAYLOAD_SIZE",
|
||
|
offset: 14,
|
||
|
length: 2,
|
||
|
"derived": true
|
||
|
}
|
||
|
],
|
||
|
PAYLOAD_OFFSET: 16
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Constants.fields.PAYLOAD_LENGTH_OFFSET = <number>Constants.fields.headers.find(header => header.name === "PAYLOAD_SIZE")?.offset;
|
||
|
Constants.fields.TOTAL_HEADERS_LENGTH = Constants.fields.headers.reduce((prev: number, curr: Header) => prev + curr.length, 0);
|
||
|
Constants.fields.PAYLOAD_MAX_LENGTH = (1024 * 64) - Constants.fields.TOTAL_HEADERS_LENGTH;
|
||
|
|
||
|
/**
|
||
|
* Convert DER key Buffer to PEM string. FIXME: break out the validity checks.
|
||
|
* @param DERKey key in DER-form
|
||
|
* @returns key in PEM form
|
||
|
*/
|
||
|
export const DERToPEM = (DERKey: Buffer) => {
|
||
|
const wrap = (buf: Buffer, type: "PUBLIC" | "PRIVATE") => Buffer.from(`-----BEGIN ${type} KEY-----
|
||
|
${buf.toString("base64")}
|
||
|
-----END ${type} KEY-----
|
||
|
`);
|
||
|
|
||
|
if (DERKey.byteLength == Constants.crypto.PRIVATE_KEY_LENGTH) {
|
||
|
const header = DERKey.subarray(0, Constants.crypto.PRIVATE_KEY_LENGTH - Constants.crypto.RAW_KEY_LENGTH);
|
||
|
if (header.equals(Constants.crypto.ENCRYPT_PRIVATE_KEY_HEADER) || header.equals(Constants.crypto.SIGN_PRIVATE_KEY_HEADER)) {
|
||
|
return wrap(DERKey, "PRIVATE");
|
||
|
}
|
||
|
}
|
||
|
else if (DERKey.byteLength == Constants.crypto.PUBLIC_KEY_LENGTH) {
|
||
|
const header = DERKey.subarray(0, Constants.crypto.PUBLIC_KEY_LENGTH - Constants.crypto.RAW_KEY_LENGTH);
|
||
|
if (header.equals(Constants.crypto.ENCRYPT_PUBLIC_KEY_HEADER) || header.equals(Constants.crypto.SIGN_PUBLIC_KEY_HEADER)) {
|
||
|
return wrap(DERKey, "PUBLIC");
|
||
|
}
|
||
|
}
|
||
|
throw new Error("Unrecognized key type");
|
||
|
};
|