Buckets:
| ; | |
| const curveJs = require('curve25519-js'); | |
| const nodeCrypto = require('crypto'); | |
| // from: https://github.com/digitalbazaar/x25519-key-agreement-key-2019/blob/master/lib/crypto.js | |
| const PUBLIC_KEY_DER_PREFIX = Buffer.from([ | |
| 48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0 | |
| ]); | |
| const PRIVATE_KEY_DER_PREFIX = Buffer.from([ | |
| 48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32 | |
| ]); | |
| const KEY_BUNDLE_TYPE = Buffer.from([5]); | |
| const prefixKeyInPublicKey = function (pubKey) { | |
| return Buffer.concat([KEY_BUNDLE_TYPE, pubKey]); | |
| }; | |
| function validatePrivKey(privKey) { | |
| if (privKey === undefined) { | |
| throw new Error("Undefined private key"); | |
| } | |
| if (!(privKey instanceof Buffer)) { | |
| throw new Error(`Invalid private key type: ${privKey.constructor.name}`); | |
| } | |
| if (privKey.byteLength != 32) { | |
| throw new Error(`Incorrect private key length: ${privKey.byteLength}`); | |
| } | |
| } | |
| function scrubPubKeyFormat(pubKey) { | |
| if (!(pubKey instanceof Buffer)) { | |
| throw new Error(`Invalid public key type: ${pubKey.constructor.name}`); | |
| } | |
| if (pubKey === undefined || ((pubKey.byteLength != 33 || pubKey[0] != 5) && pubKey.byteLength != 32)) { | |
| throw new Error("Invalid public key"); | |
| } | |
| if (pubKey.byteLength == 33) { | |
| return pubKey.slice(1); | |
| } else { | |
| console.error("WARNING: Expected pubkey of length 33, please report the ST and client that generated the pubkey"); | |
| return pubKey; | |
| } | |
| } | |
| function unclampEd25519PrivateKey(clampedSk) { | |
| const unclampedSk = new Uint8Array(clampedSk); | |
| // Fix the first byte | |
| unclampedSk[0] |= 6; // Ensure last 3 bits match expected `110` pattern | |
| // Fix the last byte | |
| unclampedSk[31] |= 128; // Restore the highest bit | |
| unclampedSk[31] &= ~64; // Clear the second-highest bit | |
| return unclampedSk; | |
| } | |
| exports.getPublicFromPrivateKey = function(privKey) { | |
| const unclampedPK = unclampEd25519PrivateKey(privKey); | |
| const keyPair = curveJs.generateKeyPair(unclampedPK); | |
| return prefixKeyInPublicKey(Buffer.from(keyPair.public)); | |
| }; | |
| exports.generateKeyPair = function() { | |
| try { | |
| const {publicKey: publicDerBytes, privateKey: privateDerBytes} = nodeCrypto.generateKeyPairSync( | |
| 'x25519', | |
| { | |
| publicKeyEncoding: { format: 'der', type: 'spki' }, | |
| privateKeyEncoding: { format: 'der', type: 'pkcs8' } | |
| } | |
| ); | |
| const pubKey = publicDerBytes.slice(PUBLIC_KEY_DER_PREFIX.length, PUBLIC_KEY_DER_PREFIX.length + 32); | |
| const privKey = privateDerBytes.slice(PRIVATE_KEY_DER_PREFIX.length, PRIVATE_KEY_DER_PREFIX.length + 32); | |
| return { | |
| pubKey: prefixKeyInPublicKey(pubKey), | |
| privKey | |
| }; | |
| } catch(e) { | |
| const keyPair = curveJs.generateKeyPair(nodeCrypto.randomBytes(32)); | |
| return { | |
| privKey: Buffer.from(keyPair.private), | |
| pubKey: prefixKeyInPublicKey(Buffer.from(keyPair.public)), | |
| }; | |
| } | |
| }; | |
| exports.calculateAgreement = function(pubKey, privKey) { | |
| pubKey = scrubPubKeyFormat(pubKey); | |
| validatePrivKey(privKey); | |
| if (!pubKey || pubKey.byteLength != 32) { | |
| throw new Error("Invalid public key"); | |
| } | |
| if(typeof nodeCrypto.diffieHellman === 'function') { | |
| const nodePrivateKey = nodeCrypto.createPrivateKey({ | |
| key: Buffer.concat([PRIVATE_KEY_DER_PREFIX, privKey]), | |
| format: 'der', | |
| type: 'pkcs8' | |
| }); | |
| const nodePublicKey = nodeCrypto.createPublicKey({ | |
| key: Buffer.concat([PUBLIC_KEY_DER_PREFIX, pubKey]), | |
| format: 'der', | |
| type: 'spki' | |
| }); | |
| return nodeCrypto.diffieHellman({ | |
| privateKey: nodePrivateKey, | |
| publicKey: nodePublicKey, | |
| }); | |
| } else { | |
| const secret = curveJs.sharedKey(privKey, pubKey); | |
| return Buffer.from(secret); | |
| } | |
| }; | |
| exports.calculateSignature = function(privKey, message) { | |
| validatePrivKey(privKey); | |
| if (!message) { | |
| throw new Error("Invalid message"); | |
| } | |
| return Buffer.from(curveJs.sign(privKey, message)); | |
| }; | |
| exports.verifySignature = function(pubKey, msg, sig, isInit) { | |
| pubKey = scrubPubKeyFormat(pubKey); | |
| if (!pubKey || pubKey.byteLength != 32) { | |
| throw new Error("Invalid public key"); | |
| } | |
| if (!msg) { | |
| throw new Error("Invalid message"); | |
| } | |
| if (!sig || sig.byteLength != 64) { | |
| throw new Error("Invalid signature"); | |
| } | |
| return isInit ? true : curveJs.verify(pubKey, msg, sig); | |
| }; | |
Xet Storage Details
- Size:
- 4.6 kB
- Xet hash:
- 0b7d96bb463e0979c01b08b767321a7ca9ac963bedaa01dedee798c68c31322b
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.