UNPKG

@shard-auth/client

Version:

Next-generation API authentication without secret keys - MPC-based authentication with FROST threshold signatures

175 lines 6.89 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.SecureStorage = void 0; const errors_1 = require("./errors"); const fs = __importStar(require("fs")); const crypto = __importStar(require("crypto")); /** * シェアの安全な保存・読み込みを行うクラス * * @example * ```typescript * // ファイルベースのストレージ * const storage = new SecureStorage('./share.key', { * password: 'strong-password' * }); * * // 環境変数からの読み込み * const storage = SecureStorage.fromEnvironment(); * ``` */ class SecureStorage { storagePath; options; shareData; constructor(storagePath, options = {}) { this.storagePath = storagePath; this.options = options; } static fromEnvironment() { const storage = new SecureStorage(); const shareDataStr = process.env.SHARD_AUTH_SHARE; if (!shareDataStr) { throw new errors_1.ShareNotFoundError('SHARD_AUTH_SHARE environment variable not set'); } try { const shareData = JSON.parse(shareDataStr); storage.shareData = { index: shareData.index, share: Buffer.from(shareData.share, 'base64'), publicKeyShare: shareData.publicKeyShare ? Buffer.from(shareData.publicKeyShare, 'base64') : Buffer.alloc(0), commitment: shareData.commitment ? Buffer.from(shareData.commitment, 'base64') : Buffer.alloc(0) }; } catch (error) { throw new errors_1.ShareNotFoundError('Invalid share data in environment variable'); } return storage; } async saveShare(share) { if (!this.storagePath) { throw new Error('Storage path not specified'); } let dataToSave; if (this.options.password) { // ランダムなソルトを生成 const salt = crypto.randomBytes(32); // パスワードからキーを導出(N=16384, r=8, p=1) const key = crypto.scryptSync(this.options.password, salt, 32, { N: 16384, r: 8, p: 1 }); const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv('aes-256-gcm', key, iv); const shareJson = JSON.stringify({ index: share.index, share: share.share.toString('base64'), publicKeyShare: share.publicKeyShare.toString('base64'), commitment: share.commitment.toString('base64') }); const encrypted = Buffer.concat([ cipher.update(shareJson, 'utf8'), cipher.final() ]); const authTag = cipher.getAuthTag(); // バージョン、ソルト、IV、authTag、暗号化データを結合 const version = Buffer.from([0x01]); // バージョン1 dataToSave = Buffer.concat([version, salt, iv, authTag, encrypted]); } else { // 暗号化なしの場合 dataToSave = Buffer.from(JSON.stringify({ index: share.index, share: share.share.toString('base64'), publicKeyShare: share.publicKeyShare.toString('base64'), commitment: share.commitment.toString('base64') })); } await fs.promises.writeFile(this.storagePath, dataToSave); } async loadShare() { // 環境変数から読み込み済みの場合 if (this.shareData) { return this.shareData; } if (!this.storagePath) { throw new errors_1.ShareNotFoundError('Storage path not specified'); } if (!fs.existsSync(this.storagePath)) { throw new errors_1.ShareNotFoundError(`Share file not found: ${this.storagePath}`); } const data = await fs.promises.readFile(this.storagePath); let shareJson; if (this.options.password) { // 復号化 // バージョンチェック const version = data[0]; if (version !== 0x01) { throw new Error('Unsupported encryption version'); } // バージョン、ソルト、IV、authTag、暗号化データを分離 const salt = data.slice(1, 33); const iv = data.slice(33, 49); const authTag = data.slice(49, 65); const encrypted = data.slice(65); // パスワードからキーを導出 const key = crypto.scryptSync(this.options.password, salt, 32, { N: 16384, r: 8, p: 1 }); const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv); decipher.setAuthTag(authTag); const decrypted = Buffer.concat([ decipher.update(encrypted), decipher.final() ]); shareJson = JSON.parse(decrypted.toString('utf8')); } else { shareJson = JSON.parse(data.toString('utf8')); } return { index: shareJson.index, share: Buffer.from(shareJson.share, 'base64'), publicKeyShare: Buffer.from(shareJson.publicKeyShare, 'base64'), commitment: Buffer.from(shareJson.commitment, 'base64') }; } } exports.SecureStorage = SecureStorage; //# sourceMappingURL=secure-storage.js.map