Browse Source

crypto node impl

user 5 years ago
parent
commit
d50978fcee

+ 18 - 0
__tests__/crypto.test.ts

@@ -0,0 +1,18 @@
+import { CryptoNode } from './../src/crypto-node';
+
+describe('crypto-node', () => {
+    const cryptoNode = new CryptoNode();
+
+    test('should generate keypair', async () => {
+      const keyPair = await cryptoNode.generateRsaKeyPair(2048);
+      expect(keyPair).toBeDefined();
+      const pubHash = keyPair.getPublicHash();
+      const sig = await keyPair.sign(Buffer.from('testing123', 'utf-8'));
+      const publicKey = keyPair.getPublicKey();
+      const exported = await keyPair.export();
+      const reconstitutedKeyPair = await cryptoNode.importRsaKeyPair(exported);
+      const reconstitutedPubHash = reconstitutedKeyPair.getPublicHash();
+      console.log('pubHash', pubHash, reconstitutedPubHash, publicKey, sig);
+      expect(pubHash).toEqual(reconstitutedPubHash);
+  });
+});

+ 6 - 4
__tests__/index.test.ts

@@ -3,10 +3,12 @@ import { BankClient } from '../src/index';
 import { StorageNode } from '../src/storage-node';
 import { IWebClient } from '../src/webclient';
 import { WebClientNode } from '../src/webclient-node';
+import { CryptoNode } from './../src/crypto-node';
 import { IWebClientOptions } from './../src/webclient-options';
 
 describe('BankClient', () => {
     const storage = new StorageNode('bankConfig');
+    const cryptoNode = new CryptoNode();
 
     test('should successfully bootstrap', async () => {
       class FakeWebClient implements IWebClient {
@@ -17,7 +19,7 @@ describe('BankClient', () => {
           throw new Error("Method not implemented.");
         }
       }
-      const bankClient = new BankClient('/urlBase', '/ipfsBase', storage, new FakeWebClient());
+      const bankClient = new BankClient('/urlBase', '/ipfsBase', storage, new FakeWebClient(), cryptoNode);
       const strapped = await bankClient.bootstrap();
       expect(strapped).toBeDefined();
   });
@@ -31,7 +33,7 @@ describe('BankClient', () => {
           return Promise.resolve('42');
         }
       }
-      const bankClient = new BankClient('/urlBase', '/ipfsBase', storage, new FakeWebClient());
+      const bankClient = new BankClient('/urlBase', '/ipfsBase', storage, new FakeWebClient(), cryptoNode);
       await bankClient.bootstrap();
       const nonce = await bankClient.getNonce();
       expect(nonce).toEqual(42);
@@ -40,7 +42,7 @@ describe('BankClient', () => {
   describe('get nonce', () => {
     test('should work with real http client', async () => {
       const webClient = new WebClientNode();
-      const bankClient = new BankClient('http://127.0.0.1:8000', '/ipfsBase', storage, webClient);
+      const bankClient = new BankClient('http://127.0.0.1:8000', '/ipfsBase', storage, webClient, cryptoNode);
       await bankClient.bootstrap();
       nock('http://127.0.0.1:8000')
         .get('/bank/nonce')
@@ -53,7 +55,7 @@ describe('BankClient', () => {
   describe('get balance', () => {
     test('should work with real http client', async () => {
       const webClient = new WebClientNode();
-      const bankClient = new BankClient('http://127.0.0.1:8000', '/ipfsBase', storage, webClient);
+      const bankClient = new BankClient('http://127.0.0.1:8000', '/ipfsBase', storage, webClient, cryptoNode);
       await bankClient.bootstrap();
       nock('http://127.0.0.1:8000')
         .post('/bank/getbalance')

+ 11 - 0
lib/crypto-node.d.ts

@@ -0,0 +1,11 @@
+/// <reference types="node" />
+import { ICrypto } from './crypto';
+import { IKeyPair } from './key-pair';
+export declare class CryptoNode implements ICrypto {
+    generateRsaKeyPair(bits: number): Promise<IKeyPair>;
+    sign(privateKeyText: string, data: Buffer): Promise<Buffer>;
+    importRsaKeyPair(serialized: string): Promise<IKeyPair>;
+    private getPublicHash;
+    private getPublicKey;
+    private export;
+}

+ 88 - 0
lib/crypto-node.js

@@ -0,0 +1,88 @@
+"use strict";
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    return new (P || (P = Promise))(function (resolve, reject) {
+        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+        step((generator = generator.apply(thisArg, _arguments || [])).next());
+    });
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const { generateKeyPair, createPublicKey, createPrivateKey, createHash, createSign } = require('crypto');
+const bs58 = require('bs58');
+class CryptoNode {
+    generateRsaKeyPair(bits) {
+        return new Promise((resolve, reject) => {
+            generateKeyPair('rsa', {
+                modulusLength: bits,
+                privateKeyEncoding: {
+                    format: 'pem',
+                    type: 'pkcs1',
+                },
+                publicKeyEncoding: {
+                    format: 'pem',
+                    type: 'spki',
+                },
+            }, (err, publicKey, privateKey) => {
+                if (err) {
+                    reject(err);
+                    return;
+                }
+                resolve({
+                    export: () => this.export(privateKey, publicKey),
+                    getPublicHash: () => this.getPublicHash(publicKey),
+                    getPublicKey: () => this.getPublicKey(publicKey),
+                    sign: (data) => this.sign(privateKey, data),
+                });
+            });
+        });
+    }
+    sign(privateKeyText, data) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const privateKey = createPrivateKey(privateKeyText);
+            const sign = createSign('SHA256');
+            sign.write(data);
+            sign.end();
+            const signature = sign.sign(privateKey, 'hex');
+            return signature;
+        });
+    }
+    importRsaKeyPair(serialized) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const { privateKey, publicKey } = JSON.parse(bs58.decode(serialized));
+            return {
+                export: () => this.export(privateKey, publicKey),
+                getPublicHash: () => this.getPublicHash(publicKey),
+                getPublicKey: () => this.getPublicKey(publicKey),
+                sign: (data) => this.sign(privateKey, data),
+            };
+        });
+    }
+    getPublicHash(publicKeyText) {
+        const publicKey = createPublicKey(publicKeyText);
+        const derBytes = publicKey.export({
+            type: 'spki',
+            format: 'der'
+        });
+        const sha256 = createHash('sha256');
+        sha256.update(derBytes);
+        const pubHash = bs58.encode(sha256.digest());
+        return pubHash;
+    }
+    getPublicKey(publicKeyText) {
+        const publicKey = createPublicKey(publicKeyText);
+        const derBytes = publicKey.export({
+            type: 'spki',
+            format: 'der'
+        });
+        return derBytes.toString('hex');
+    }
+    export(privateKey, publicKey) {
+        return __awaiter(this, void 0, void 0, function* () {
+            const jsonString = JSON.stringify({ privateKey, publicKey });
+            return bs58.encode(Buffer.from(jsonString, 'utf-8'));
+        });
+    }
+}
+exports.CryptoNode = CryptoNode;
+//# sourceMappingURL=crypto-node.js.map

File diff suppressed because it is too large
+ 1 - 0
lib/crypto-node.js.map


+ 5 - 0
lib/crypto.d.ts

@@ -0,0 +1,5 @@
+import { IKeyPair } from "./key-pair";
+export interface ICrypto {
+    generateRsaKeyPair(bits: number): Promise<IKeyPair>;
+    importRsaKeyPair(serialized: string): Promise<IKeyPair>;
+}

+ 3 - 0
lib/crypto.js

@@ -0,0 +1,3 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//# sourceMappingURL=crypto.js.map

+ 1 - 0
lib/crypto.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":""}

+ 3 - 2
lib/index.d.ts

@@ -1,6 +1,7 @@
 import { ContactBook } from './contact-book';
 import { ContactItem } from './contact-item';
 import { ContentItem } from './content-item';
+import { ICrypto } from './crypto';
 import { Storage } from './storage';
 import { UploadItemParameters } from './upload-item-parameters';
 import { IWebClient } from './webclient';
@@ -9,6 +10,7 @@ export declare class BankClient {
     private ipfsUrlBase;
     private storage;
     private webClient;
+    private crypto;
     static parseBankLink(bankLink: string): {
         host: string | undefined;
         address: string;
@@ -18,7 +20,7 @@ export declare class BankClient {
     private wsUrlBase;
     private bootstrapPromise;
     private bootstrapResult;
-    constructor(urlBase: string, ipfsUrlBase: string, storage: Storage, webClient: IWebClient);
+    constructor(urlBase: string, ipfsUrlBase: string, storage: Storage, webClient: IWebClient, crypto: ICrypto);
     getPub(): Promise<string>;
     bootstrap(): any;
     getNonce(): Promise<number>;
@@ -43,6 +45,5 @@ export declare class BankClient {
     };
     runAgent(address: string, topic: string, storage: Storage, itemProcessCallback: (item: ContentItem | ContactItem) => Promise<any>): Promise<void>;
     private connectWebsocket;
-    private getPriv;
     private makePlaintextPayload;
 }

+ 38 - 64
lib/index.js

@@ -11,7 +11,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
     return (mod && mod.__esModule) ? mod : { "default": mod };
 };
 Object.defineProperty(exports, "__esModule", { value: true });
-const crypto = require("libp2p-crypto");
 const ws_1 = __importDefault(require("ws"));
 const contact_address_1 = require("./contact-address");
 const contact_book_1 = require("./contact-book");
@@ -19,11 +18,12 @@ const contact_item_1 = require("./contact-item");
 const content_item_1 = require("./content-item");
 const util_1 = require("./util");
 class BankClient {
-    constructor(urlBase, ipfsUrlBase, storage, webClient) {
+    constructor(urlBase, ipfsUrlBase, storage, webClient, crypto) {
         this.urlBase = urlBase;
         this.ipfsUrlBase = ipfsUrlBase;
         this.storage = storage;
         this.webClient = webClient;
+        this.crypto = crypto;
         this.wsUrlBase = urlBase.replace(/^http/i, 'ws');
     }
     static parseBankLink(bankLink) {
@@ -48,12 +48,15 @@ class BankClient {
     getPub() {
         return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
             yield this.bootstrap();
-            this.getPriv().id((idErr, pubHash) => {
-                if (idErr) {
-                    return reject(idErr);
+            try {
+                if (!this.privateKey) {
+                    throw new Error('missing privateKey');
                 }
-                resolve(pubHash);
-            });
+                resolve(this.privateKey.getPublicHash());
+            }
+            catch (e) {
+                reject(e);
+            }
         }));
     }
     bootstrap() {
@@ -64,38 +67,23 @@ class BankClient {
             return this.bootstrapPromise;
         }
         return this.bootstrapPromise = new Promise((resolve, reject) => {
-            this.storage.get('notaprivatekey').then(privateKeyFromStorage => {
+            this.storage.get('notaprivatekey').then((privateKeyFromStorage) => __awaiter(this, void 0, void 0, function* () {
                 if (privateKeyFromStorage == null) {
                     console.log('no private key in storage. generating new');
-                    crypto.keys.generateKeyPair('RSA', 2048, (generateErr, privateKey) => {
-                        if (generateErr) {
-                            return reject(generateErr);
-                        }
-                        privateKey.export('password', (exportErr, exportResult) => {
-                            if (exportErr) {
-                                return reject(exportErr);
-                            }
-                            this.storage.set('notaprivatekey', exportResult).then(err => {
-                                // whatever
-                            }).catch(reject);
-                            this.privateKey = privateKey;
-                            resolve(true);
-                        });
-                    });
+                    const privateKey = yield this.crypto.generateRsaKeyPair(2048);
+                    const exportResult = yield privateKey.export();
+                    this.storage.set('notaprivatekey', exportResult).then(err => {
+                        // whatever
+                    }).catch(reject);
+                    this.privateKey = privateKey;
+                    resolve(true);
                 }
                 else {
                     // console.log('importing privatekey');
-                    crypto.keys.import(privateKeyFromStorage, 'password', (err, importedPrivateKey) => {
-                        if (err) {
-                            return reject(err);
-                        }
-                        this.privateKey = importedPrivateKey;
-                        // console.log(this.getPublicKeyString());
-                        // console.log(privateKeyFromStorage);
-                        resolve(true);
-                    });
+                    this.privateKey = yield this.crypto.importRsaKeyPair(privateKeyFromStorage);
+                    resolve(true);
                 }
-            }).catch(reject);
+            })).catch(reject);
         });
     }
     getNonce() {
@@ -429,39 +417,25 @@ class BankClient {
             resolve();
         }));
     }
-    getPriv() {
-        if (!this.privateKey) {
-            throw new Error('missing private key');
-        }
-        return this.privateKey;
-    }
     makePlaintextPayload(message) {
-        const messageBytes = Buffer.from(message, 'utf-8');
-        return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
+        return __awaiter(this, void 0, void 0, function* () {
+            const messageBytes = Buffer.from(message, 'utf-8');
             yield this.bootstrap();
-            this.privateKey.sign(messageBytes, (signErr, signatureBytes) => __awaiter(this, void 0, void 0, function* () {
-                if (signErr) {
-                    reject(signErr);
-                    return;
-                }
-                const publicDERBytes = this.privateKey.public.bytes;
-                this.privateKey.id((idErr, pubHash) => {
-                    if (idErr) {
-                        reject(idErr);
-                        return;
-                    }
-                    const result = {
-                        date: new Date().toISOString(),
-                        msg: util_1.encodeHex(messageBytes),
-                        pub: util_1.encodeHex(publicDERBytes),
-                        pubHash,
-                        sig: util_1.encodeHex(signatureBytes),
-                    };
-                    // console.log('result', result, signatureBytes);
-                    resolve(result);
-                });
-            }));
-        }));
+            if (!this.privateKey) {
+                throw new Error('missing privateKey');
+            }
+            const signatureBytes = yield this.privateKey.sign(messageBytes);
+            const publicKey = yield this.privateKey.getPublicKey();
+            const pubHash = yield this.privateKey.getPublicHash();
+            const result = {
+                date: new Date().toISOString(),
+                msg: util_1.encodeHex(messageBytes),
+                pub: util_1.encodeHex(Buffer.from(publicKey, 'hex')),
+                pubHash,
+                sig: util_1.encodeHex(signatureBytes),
+            };
+            return result;
+        });
     }
 }
 exports.BankClient = BankClient;

File diff suppressed because it is too large
+ 1 - 1
lib/index.js.map


+ 7 - 0
lib/key-pair.d.ts

@@ -0,0 +1,7 @@
+/// <reference types="node" />
+export interface IKeyPair {
+    getPublicKey(): string;
+    getPublicHash(): string;
+    sign(data: Buffer): Promise<Buffer>;
+    export(): Promise<string>;
+}

+ 3 - 0
lib/key-pair.js

@@ -0,0 +1,3 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+//# sourceMappingURL=key-pair.js.map

+ 1 - 0
lib/key-pair.js.map

@@ -0,0 +1 @@
+{"version":3,"file":"key-pair.js","sourceRoot":"","sources":["../src/key-pair.ts"],"names":[],"mappings":""}

+ 2 - 1
lib/sample.js

@@ -12,7 +12,8 @@ const index_1 = require("./index");
 const storage_node_1 = require("./storage-node");
 const webclient_node_1 = require("./webclient-node");
 const host = 'http://127.0.0.1:8082';
-const bankClient = new index_1.BankClient(host, 'https://distributing.fun', new storage_node_1.StorageNode('bankClient'), new webclient_node_1.WebClientNode());
+const crypto_node_1 = require("./../src/crypto-node");
+const bankClient = new index_1.BankClient(host, 'https://distributing.fun', new storage_node_1.StorageNode('bankClient'), new webclient_node_1.WebClientNode(), new crypto_node_1.CryptoNode());
 (() => __awaiter(this, void 0, void 0, function* () {
     yield bankClient.bootstrap();
     const peerId = yield bankClient.getPub();

File diff suppressed because it is too large
+ 1 - 1
lib/sample.js.map


+ 4 - 4
package-lock.json

@@ -956,9 +956,9 @@
       }
     },
     "base-x": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.6.tgz",
-      "integrity": "sha512-4PaF8u2+AlViJxRVjurkLTxpp7CaFRD/jo5rPT9ONnKxyhQ8f59yzamEvq7EkriG56yn5On4ONyaG75HLqr46w==",
+      "version": "3.0.8",
+      "resolved": "https://npm.bgs.dev/base-x/-/base-x-3.0.8.tgz",
+      "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==",
       "requires": {
         "safe-buffer": "^5.0.1"
       }
@@ -1124,7 +1124,7 @@
     },
     "bs58": {
       "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
+      "resolved": "https://npm.bgs.dev/bs58/-/bs58-4.0.1.tgz",
       "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
       "requires": {
         "base-x": "^3.0.2"

+ 1 - 0
package.json

@@ -32,6 +32,7 @@
     "typescript": "^3.5.3"
   },
   "dependencies": {
+    "bs58": "^4.0.1",
     "express": "^4.17.1",
     "libp2p-crypto": "^0.16.1",
     "request": "^2.88.0",

+ 86 - 0
src/crypto-node.ts

@@ -0,0 +1,86 @@
+import fs = require('fs');
+const { generateKeyPair, createPublicKey, createPrivateKey, createHash, createSign } = require('crypto');
+const bs58 = require('bs58');
+
+import { ICrypto } from './crypto';
+import { IKeyPair } from './key-pair';
+
+export class CryptoNode implements ICrypto {
+
+    public generateRsaKeyPair(bits: number): Promise<IKeyPair> {
+        return new Promise((resolve, reject) => {
+            generateKeyPair('rsa', {
+                modulusLength: bits,
+                privateKeyEncoding: {
+                    format: 'pem',
+                    type: 'pkcs1',
+                    
+                  },
+                publicKeyEncoding: {
+                    format: 'pem',
+                  type: 'spki',
+                  
+                },
+            }, (err, publicKey: string, privateKey: string) => {
+                  if (err) {
+                      reject(err);
+                      return;
+                  }
+                  resolve({
+                      export: () => this.export(privateKey, publicKey),
+                      getPublicHash: () => this.getPublicHash(publicKey),
+                      getPublicKey: () => this.getPublicKey(publicKey),
+                      sign: (data: Buffer) => this.sign(privateKey, data),
+                  });
+                });
+            });
+    }
+
+    public async sign(privateKeyText: string, data: Buffer): Promise<Buffer> {
+      const privateKey = createPrivateKey(privateKeyText);
+      const sign = createSign('SHA256');
+      sign.write(data);
+      sign.end();
+      const signature = sign.sign(privateKey, 'hex');
+      return signature;
+    }
+
+    public async importRsaKeyPair(serialized: string): Promise<IKeyPair> {
+        const { privateKey, publicKey } = JSON.parse(bs58.decode(serialized));
+
+        return {
+          export: () => this.export(privateKey, publicKey),
+          getPublicHash: () => this.getPublicHash(publicKey),
+          getPublicKey: () => this.getPublicKey(publicKey),
+          sign: (data: Buffer) => this.sign(privateKey, data),
+      };
+    }
+
+    private getPublicHash(publicKeyText: string): string {
+      const publicKey = createPublicKey(publicKeyText);
+      const derBytes = publicKey.export({
+        type: 'spki',
+        format: 'der'
+      });
+
+      const sha256 = createHash('sha256');
+      sha256.update(derBytes);
+      const pubHash = bs58.encode(sha256.digest());
+      return pubHash;
+    }
+
+    private getPublicKey(publicKeyText: string): string {
+      const publicKey = createPublicKey(publicKeyText);
+      const derBytes = publicKey.export({
+        type: 'spki',
+        format: 'der'
+      });
+      return derBytes.toString('hex');
+    }
+
+    private async export(privateKey: string, publicKey: string): Promise<string> {
+        const jsonString = JSON.stringify({privateKey, publicKey});
+        return bs58.encode(Buffer.from(jsonString, 'utf-8'));
+    }
+
+}

+ 9 - 0
src/crypto.ts

@@ -0,0 +1,9 @@
+import { IKeyPair } from "./key-pair";
+
+export interface ICrypto {
+
+    generateRsaKeyPair(bits: number): Promise<IKeyPair>;
+
+    importRsaKeyPair(serialized: string): Promise<IKeyPair>;
+
+}

+ 38 - 67
src/index.ts

@@ -1,11 +1,11 @@
-import crypto = require('libp2p-crypto');
+import { IKeyPair } from './key-pair';
 import WebSocket from 'ws';
 import { ContactAddress } from './contact-address';
 import { ContactBook } from './contact-book';
 import { ContactItem } from './contact-item';
 import { ContentItem } from './content-item';
 import { ContentParams } from './content-params';
-import RsaPrivateKey = crypto.keys;
+import { ICrypto } from './crypto';
 import { Storage } from './storage';
 import { UploadItemParameters } from './upload-item-parameters';
 import { encodeHex, mergeDeep, uuid } from './util';
@@ -32,24 +32,26 @@ export class BankClient {
     return { host, address, topic };
   }
 
-    private privateKey: RsaPrivateKey | undefined;
+    private privateKey: IKeyPair | undefined;
     private wsUrlBase: string;
     private bootstrapPromise: any;
     private bootstrapResult: any;
     
-    constructor(private urlBase: string, private ipfsUrlBase: string, private storage: Storage, private webClient: IWebClient) {
+    constructor(private urlBase: string, private ipfsUrlBase: string, private storage: Storage, private webClient: IWebClient, private crypto: ICrypto) {
       this.wsUrlBase = urlBase.replace(/^http/i, 'ws');
     }
 
     public getPub(): Promise<string> {
       return new Promise(async (resolve, reject) => {
         await this.bootstrap();
-        this.getPriv().id((idErr, pubHash) => {
-          if (idErr) {
-            return reject(idErr);
+        try {
+          if (!this.privateKey) {
+            throw new Error('missing privateKey');
           }
-          resolve(pubHash);
-        });
+          resolve(this.privateKey.getPublicHash());
+        } catch (e) {
+          reject(e);
+        }
       });
     }
   
@@ -61,35 +63,21 @@ export class BankClient {
         return this.bootstrapPromise;
       }
       return this.bootstrapPromise = new Promise((resolve, reject) => {
-        this.storage.get('notaprivatekey').then(privateKeyFromStorage => {
+        this.storage.get('notaprivatekey').then(async (privateKeyFromStorage) => {
           if (privateKeyFromStorage == null) {
             console.log('no private key in storage. generating new');
-            crypto.keys.generateKeyPair('RSA', 2048, (generateErr, privateKey) => {
-              if (generateErr) {
-                return reject(generateErr);
-              }
-              privateKey.export('password', (exportErr, exportResult) => {
-                if (exportErr) {
-                  return reject(exportErr);
-                }
-                this.storage.set('notaprivatekey', exportResult).then(err => {
-                    // whatever
-                }).catch(reject);
-                this.privateKey = privateKey;
-                resolve(true);
-              });
-            });
+            const privateKey = await this.crypto.generateRsaKeyPair(2048);
+            const exportResult = await privateKey.export();
+
+            this.storage.set('notaprivatekey', exportResult).then(err => {
+                // whatever
+            }).catch(reject);
+            this.privateKey = privateKey;
+            resolve(true);
           } else {
             // console.log('importing privatekey');
-            crypto.keys.import(privateKeyFromStorage, 'password', (err, importedPrivateKey) => {
-              if (err) {
-                return reject(err);
-              }
-              this.privateKey = importedPrivateKey;
-              // console.log(this.getPublicKeyString());
-              // console.log(privateKeyFromStorage);
-              resolve(true);
-            });
+            this.privateKey = await this.crypto.importRsaKeyPair(privateKeyFromStorage);
+            resolve(true);
           }
         }).catch(reject);
       });
@@ -429,40 +417,23 @@ export class BankClient {
     
   }
 
-  private getPriv(): RsaPrivateKey {
+  private async makePlaintextPayload(message: string) {
+    const messageBytes = Buffer.from(message, 'utf-8');
+    await this.bootstrap();
     if (!this.privateKey) {
-      throw new Error('missing private key');
+      throw new Error('missing privateKey');
     }
-    return this.privateKey;
-  }
-
-  private makePlaintextPayload(message: string) {
-    const messageBytes = Buffer.from(message, 'utf-8');
-
-    return new Promise(async (resolve, reject) => {
-      await this.bootstrap();
-      this.privateKey.sign(messageBytes, async (signErr, signatureBytes) => {
-        if (signErr) {
-          reject(signErr);
-          return;
-        }
-        const publicDERBytes = this.privateKey.public.bytes;
-        this.privateKey.id((idErr, pubHash) => {
-          if (idErr) {
-            reject(idErr);
-            return;
-          }
-          const result = {
-            date: new Date().toISOString(),
-            msg: encodeHex(messageBytes),
-            pub: encodeHex(publicDERBytes),
-            pubHash,
-            sig: encodeHex(signatureBytes),
-          };
-          // console.log('result', result, signatureBytes);
-          resolve(result);
-        });
-      });
-    });
+    const signatureBytes = await this.privateKey.sign(messageBytes);
+    const publicKey = await this.privateKey.getPublicKey();
+    const pubHash = await this.privateKey.getPublicHash();
+
+    const result = {
+      date: new Date().toISOString(),
+      msg: encodeHex(messageBytes),
+      pub: encodeHex(Buffer.from(publicKey, 'hex')),
+      pubHash,
+      sig: encodeHex(signatureBytes),
+    };
+    return result;
   }
 }

+ 11 - 0
src/key-pair.ts

@@ -0,0 +1,11 @@
+export interface IKeyPair {
+    
+    getPublicKey(): string;
+
+    getPublicHash(): string;
+
+    sign(data: Buffer): Promise<Buffer>;
+
+    export(): Promise<string>;
+
+}

+ 2 - 1
src/sample.ts

@@ -2,8 +2,9 @@ import { BankClient } from './index';
 import { StorageNode } from './storage-node';
 import { WebClientNode } from './webclient-node';
 const host = 'http://127.0.0.1:8082';
+import { CryptoNode } from './../src/crypto-node';
 
-const bankClient = new BankClient(host, 'https://distributing.fun', new StorageNode('bankClient'), new WebClientNode());
+const bankClient = new BankClient(host, 'https://distributing.fun', new StorageNode('bankClient'), new WebClientNode(), new CryptoNode());
 
 (async () => {
     await bankClient.bootstrap();