Ed25519應用,node,js生成經常使用的密鑰對

Ed25519簽名算法介紹

Ed25519做者

Daniel J. Bernstein 是世界著名的密碼學家javascript

優點

徹底開放設計,算法各個參數直接了當,明確,很大的機率經過緩存、時間、惡意輸入摧毀安全性,而 25519 系列橢圓曲線通過特別設計,儘量的將出錯的機率降到了最低,25519 系列曲線是目前最快的橢圓曲線加密算法,一個4核2.4GHz 的 Westmere cpu,每秒能夠驗證 71000 個簽名,吊打同類:橢圓曲線是 NISTjava

基本特色

公共鑰只有32字節,私鑰只有64字節node

實戰node,js生成Ed25519密鑰對

目標

經過tweetnacl生成原始的Uint8Array密鑰對,生成公鑰,私鑰類型首字母G,S寫入Buffer,而後私鑰寫入Buffer,經過上面Buffer計算校驗碼再次寫入buffer,最後使用base32編碼。生成用戶常規保存的字符串。git

首先安裝依賴包

npm I tweetnacl crc lodash base32.js —save
解釋簡單解釋說明下包的做用
tweetnacl: 最核心的包,是用javascript接口實現的TweetNaci/Naci端口,它實現了密鑰加密解密,公鑰驗證加密,公共簽名,hash等。咱們將使用這個庫生成,原始的Uint8Array密鑰對。也能夠本身隨機一個64byte私鑰,而後解析爲keypair。
crc:生成校驗碼的
lodash:是一個一致性、模塊化、高性能的 JavaScript 實用工具庫。
base32.js:因爲原生方法,只有base64,因此引入base32.js進行編碼解碼github

具體代碼實現

//各類引入  
const nacl = require(「tweetnacl");
const crc = require("crc");
const base32 = require("base32.js")
const isUndefined = require("lodash/isUndefined");
const isNull = require("lodash/isNull");
const isString = require("lodash/isString");
const versionBytes = {
  ed25519PublicKey:  6 << 3, // G
  ed25519SecretSeed: 18 << 3, // S
  preAuthTx:         19 << 3, // T
  sha256Hash:        23 << 3  // X
};

//封裝一個類,構造函數中生成keypair,提供靜態編碼解碼公鑰私鑰方法
class Keypair {
    constructor(){
        this.orikeypair = nacl.sign.keyPair();
        this.publicKey = Buffer.from(this.orikeypair.publicKey);
        console.log(this.orikeypair.publicKey);
        this.privateKey = Buffer.from(this.orikeypair.secretKey);
    }
    static encodeCheck(versionByteName, data) {
        if (isNull(data) || isUndefined(data)) {
            throw new Error("cannot encode null data");
        }
        let versionByte = versionBytes[versionByteName];
        if (isUndefined(versionByte)) {
            throw new Error(`${versionByteName} is not a valid version byte name.  expected one of "ed25519PublicKey", "ed25519SecretSeed", "preAuthTx", "sha256Hash"`);
        }
        data  = Buffer.from(data);
        let versionBuffer = Buffer.from([versionByte]);
        let payload       = Buffer.concat([versionBuffer, data]);
        let checksum      = calculateChecksum(payload);
        let unencoded     = Buffer.concat([payload, checksum]);
        return base32.encode(unencoded);
    }
    static decodeCheck(versionByteName, encoded) {
        if (!isString(encoded)) {
          throw new TypeError('encoded argument must be of type String');
        }
        let decoded     = base32.decode(encoded);
        let versionByte = decoded[0];
        let payload     = decoded.slice(0, -2);
        let data        = payload.slice(1);
        let checksum    = decoded.slice(-2);
        if (encoded != base32.encode(decoded)) {
          throw new Error('invalid encoded string');
        }
        let expectedVersion = versionBytes[versionByteName];
        if (isUndefined(expectedVersion)) {
          throw new Error(`${versionByteName} is not a valid version byte name.  expected one of "accountId" or "seed"`);
        }
        if (versionByte !== expectedVersion) {
          throw new Error(`invalid version byte. expected ${expectedVersion}, got ${versionByte}`);
        }
        let expectedChecksum = calculateChecksum(payload);
        if (!verifyChecksum(expectedChecksum, checksum)) {
          throw new Error(`invalid checksum`);
        }
        return Buffer.from(data);
    } 
}
function calculateChecksum(payload) {
  // This code calculates CRC16-XModem checksum of payload
  // and returns it as Buffer in little-endian order.
  let checksum = Buffer.alloc(2);
  checksum.writeUInt16LE(crc.crc16xmodem(payload), 0);
  return checksum;
}
//測試使用
let newKeypair = new Keypair();
console.log(newKeypair.publicKey);
let newPublic = Keypair.encodeCheck("ed25519PublicKey",newKeypair.publicKey);
let newPrivate = Keypair.encodeCheck("ed25519SecretSeed",newKeypair.privateKey);
let publicBuffer = Keypair.decodeCheck("ed25519PublicKey",newPublic);
console.log(newPublic,newPrivate);
console.log(publicBuffer);

說明

相關包的詳細api能夠直接複製包名字在github查找算法

相關文章
相關標籤/搜索