1. 程式人生 > >公鑰私鑰加密和SHA256

公鑰私鑰加密和SHA256

公鑰和私鑰

公鑰(Public Key)與私鑰(Private Key)是通過一種演算法得到的一個金鑰對(即一個公鑰和一個私鑰),公鑰是金鑰對中公開的部分,私鑰則是非公開的部分。公鑰通常用於加密會話金鑰、驗證數字簽名,或加密可以用相應的私鑰解密的資料。

公鑰和私鑰是成對出現的,我們會保留有自己的私鑰,同時公開自己的公鑰。一個很典型的例子是GitHub的使用。我們通常不會使用賬號密碼來管理自己的專案,而是通過將自己的公鑰上傳到GitHub的裡,而自己的電腦裡則保留有相對應的私鑰,從而達到免密碼提交程式碼。

當然私鑰和公鑰對是唯一的,而你也可以隨時重新生成自己的公鑰和私鑰密碼對,但當你從新生成金鑰對並覆蓋了就有的金鑰時,你之前的公鑰就作廢了。

簡單來說就是:
公鑰加密,私鑰解密,
私鑰簽名,公鑰驗證。

SHA256

SHA256是一種安全雜湊演算法。

簡單介紹一下就是,對於任何一段資訊,通過SHA256變換之後,都會是一個固定的 256 位由 0 和 1 組成的輸出。同時,對於相同的資訊,輸出一樣,而對於不一樣的資訊,輸出則有很大的區別,即使只有一丁點的輸入不一樣,輸出也會有非常大的不一樣。

同時,雖然資訊輸入是無限的,而 SHA256 的輸出是有限的(256位),但是根據我們目前的條件和計算能力水平來說,幾乎找不到有兩個不同的輸入,可以得到相同的輸出。也即我們可以認為是不可能的。

程式碼

接下來我們,我們使用 Js 的 ursa 庫來生成公鑰和私鑰

generatePrivateAndPubKey.js

const ursa = require("ursa");
const fs = require("fs");
const path = require("path");

const MODULUSBIT = 1024;

class Key {
  static generateKeys(pathName) {
    const key = ursa.generatePrivateKey(MODULUSBIT, 65537);

    const privatePem = key.toPrivatePem("utf8");
    const
privateKey = ursa.createPrivateKey(privatePem); // generate private key const privateFileName = path.join(pathName, "private.pem"); const publicPem = key.toPublicPem("utf8"); const publicKey = ursa.createPublicKey(publicPem); // generate public key const publicFileName = path.join(pathName, "public.pub"); if (!fs.existsSync(pathName)) { fs.mkdirSync(pathName); } fs.writeFileSync(privateFileName, privatePem, "utf8"); fs.writeFileSync(publicFileName, publicPem, "utf8"); return { privateKey: privateKey, publicKey: publicKey }; } static signMessage(privateKey, message) {} } module.exports = exports = Key;

test.js

const Key = require("./generatePrivateAndPubKey.js");
const SHA256 = require("crypto-js/sha256");
const ursa = require("ursa");

const fs = require("fs");
const encoding = "base64";
const algorigthm = "sha256";
const message = "Hello world";

let buffer = new Buffer(message, encoding);

// use Bob's private key to signed message
const BobKeys = Key.generateKeys("Bob");
const signedMessage = BobKeys.privateKey.sign(
  algorigthm,
  buffer,
  encoding,
  encoding
);

// use Bob's public to verify the message
const isValid = BobKeys.publicKey.verify(
  algorigthm,
  buffer,
  signedMessage,
  encoding
);

// use Bob's public key to encrypt message
const encrypted = BobKeys.publicKey.encrypt(message, encoding, "base64");
// use Bob's private key to dencrypt message
const decrypted = BobKeys.privateKey.decrypt(encrypted, "base64", encoding);

console.log("Original Message:", message, "\n");
console.log("Singed Message:", signedMessage, "\n");
console.log("isValid", isValid, "\n");
console.log("Encrypted message:", encrypted, "\n");
console.log("Decrypted message:", decrypted, "\n");

輸出

Original Message: Hello world

Singed Message: ARSvIgmY7iIznhuk70stOIj8bBzj4A58wlHKKUPerU1WRob+Mk3U7p5hEhX4+lyLi/F6m3O4dfJ4dESQ2aO+deocjQd4F4zv2s2RC7AhST0nIT0F4iJYAct73R1Azum8MQK+7tesKLUYPLTfjQcvaNDhG+yDl9KfMrGO/Jgtoms=

isValid true

Encrypted message: 5ItG99B3H0h4lbpDDLwD8rza1nPWleWlvOok475lFLxYaI5AvdDetGZq+Cw5K/kcOb6qnpYcoNij1OCgiuSAad352vc596jEFExRZlhsTCqXTtqXblfEPOn4PUtrzrS/jn2FEUke3icF4fqtvVKFYeYpTl1rfrANhe3NrY9F5ik=

Decrypted message: HelloworlQ==

接下來,讓我們來測試一下 SHA256

let sha256Message = SHA256("1111").toString();
console.log("1111 After SHA256:", sha256Message, "\n");

sha256Message = SHA256("1112").toString();
console.log("1112 After SHA256:", sha256Message, "\n");

sha256Message = SHA256("111111111111111111").toString();
console.log("111111111111111111 After SHA256:", sha256Message, "\n");

sha256Message = SHA256("111211111111111111").toString();
console.log("111211111111111111 After SHA256:", sha256Message, "\n");

/*
Output:

1111 After SHA256: 0ffe1abd1a08215353c233d6e009613e95eec4253832a761af28ff37ac5a150c

1112 After SHA256: fe91a760983d401d9b679fb092b689488d1f46d92f3af5e9e93363326f3e8aa4

111111111111111111 After SHA256: 26980a9bf7dba794bd14eae90dbda34109d37f66950c16cce7b87dffd4535b40

111211111111111111 After SHA256: 308c3ae83c039dee107a232c4ccb4ee4a65ef3fb1e41357a6b9b240e88b09c0e
*/

Base64 和 Base58

比特幣裡用的編碼方式是 Base58, 但是因為我們使用的測試庫 ursa並不支援 Base58, 因此我們只能使用Base64。Base64 和 Base64 並沒有什麼太大的區別,在這裡並不會影響我們對加解密,數字簽名的理解。

為什麼比特幣要使用Base58呢?這裡引用一下比特幣原始碼裡的註釋。

//
// Why base-58 instead of standard base-64 encoding?
// - Don’t want 0OIl characters that look the same in some fonts and
// could be used to create visually identical looking account numbers.
// - A string with non-alphanumeric characters is not as easily accepted as an account number.
// - E-mail usually won’t line-break if there’s no punctuation to break at.
// - Doubleclicking selects the whole number as one word if it’s all alphanumeric.
//

簡單來說就是去掉 O, I, L 這些不好區分的字元。