micro-key-producer
Version:
Produces secure keys and passwords. Supports SSH, PGP, BLS, OTP, and many others
81 lines • 3.04 kB
JavaScript
/*! micro-key-producer - MIT License (c) 2024 Paul Miller (paulmillr.com) */
import { ed25519 } from '@noble/curves/ed25519';
import { sha256 } from '@noble/hashes/sha256';
import { concatBytes, randomBytes } from '@noble/hashes/utils';
import { base64 } from '@scure/base';
import * as P from 'micro-packed';
import { base64armor } from './utils.js';
export const SSHString = P.string(P.U32BE);
export const SSHBuf = P.bytes(P.U32BE);
export const SSHKeyType = P.magic(SSHString, 'ssh-ed25519');
export const PublicKey = P.struct({ keyType: SSHKeyType, pubKey: P.bytes(P.U32BE) });
const PrivateKey = P.padRight(8, P.struct({
check1: P.bytes(4),
check2: P.bytes(4),
keyType: SSHKeyType,
pubKey: SSHBuf,
privKey: SSHBuf,
comment: SSHString,
}), (i) => i + 1);
// https://tools.ietf.org/html/draft-miller-ssh-agent-02#section-4.5
export const AuthData = P.struct({
nonce: SSHBuf,
userAuthRequest: P.U8, // == 50
user: SSHString,
conn: SSHString,
auth: SSHString,
haveSig: P.U8, // == 1
keyType: SSHKeyType,
pubKey: P.prefix(P.U32BE, PublicKey),
});
export const PrivateExport = base64armor('openssh private key', 70, P.struct({
magic: P.magicBytes('openssh-key-v1\0'),
// Only decrypted ed25519 keys supported for now
ciphername: P.magic(SSHString, 'none'),
kdfname: P.magic(SSHString, 'none'),
kdfopts: P.magic(SSHString, ''),
keys: P.array(P.U32BE, P.struct({
pubKey: P.prefix(P.U32BE, PublicKey),
privKey: P.prefix(P.U32BE, PrivateKey),
})),
}));
export function formatPublicKey(bytes, comment) {
const blob = PublicKey.encode({ pubKey: bytes });
return `ssh-ed25519 ${base64.encode(blob)}${comment ? ` ${comment}` : ''}`;
}
export function getFingerprint(bytes) {
const blob = PublicKey.encode({ pubKey: bytes });
// ssh-keygen -l -f ~/.ssh/id_ed25519
// 256 SHA256:+WK/Sl4XJjoxDlAWYuhq4Fl2hka9j3GOUjYczQkqnCI user@comp.local (ED25519)
return `SHA256:${base64.encode(sha256(blob)).replace(/=$/, '')}`;
}
// For determenistic generation in tests
export function getKeys(privateKey, comment, checkBytes = randomBytes(4)) {
const pubKey = ed25519.getPublicKey(privateKey);
return {
publicKeyBytes: pubKey,
publicKey: formatPublicKey(pubKey, comment),
fingerprint: getFingerprint(pubKey),
privateKey: PrivateExport.encode({
keys: [
{
pubKey: { pubKey },
privKey: {
// Check bytes, should be same
check1: checkBytes,
check2: checkBytes,
pubKey,
privKey: concatBytes(privateKey, pubKey),
comment: comment || '',
},
},
],
}),
};
}
// For SSH Agents
export function authSign(privateKey, data) {
return ed25519.sign(AuthData.encode(data), privateKey);
}
export default getKeys;
//# sourceMappingURL=ssh.js.map