• Trang chủ
  • Blockchain
  • Làm thế nào để mã hóa dữ liệu cần được giải mã trong node.js?
64 lượt xem

Làm thế nào để mã hóa dữ liệu cần được giải mã trong node.js?


Cập nhật vào 12-DEC-2019

Không giống như 1 số ít chính sách khác như CBC, chính sách GCM không nhu yếu IV không hề đoán trước được. Yêu cầu duy nhất là IV phải là duy nhất cho mỗi lệnh gọi với một khóa nhất định. Nếu nó lặp lại một lần cho một khóa nhất định, bảo mật thông tin hoàn toàn có thể bị xâm phạm. Một cách thuận tiện để đạt được điều này là sử dụng IV ngẫu nhiên từ một trình tạo số ngẫu nhiên giả mạnh như được hiển thị bên dưới .Sử dụng một chuỗi hoặc dấu thời hạn làm IV cũng hoàn toàn có thể, nhưng nó hoàn toàn có thể không tầm thường như âm thanh. Ví dụ : nếu mạng lưới hệ thống không theo dõi đúng mực những trình tự đã được sử dụng làm IV trong một kho tàng trữ liên tục, một lệnh gọi hoàn toàn có thể lặp lại một IV sau khi mạng lưới hệ thống khởi động lại. Tương tự như vậy, không có đồng hồ đeo tay tuyệt vời. Điều chỉnh đồng hồ đeo tay máy tính, v.v.

Ngoài ra, khóa phải được xoay sau mỗi 2 ^ 32 lần gọi. Để biết thêm chi tiết về yêu cầu IV, hãy tham khảo câu trả lời này và các khuyến nghị của NIST .

Cập nhật vào ngày 30 tháng 7 năm 2019

Vì câu trả lời đang nhận được nhiều lượt xem và phiếu bầu hơn, tôi nghĩ điều đáng nói là đoạn mã bên dưới đã sử dụng phương thức * Đồng bộ hóa – crypto.scryptSync. Bây giờ điều đó là tốt nếu mã hóa hoặc giải mã được thực hiện trong quá trình khởi tạo ứng dụng. Nếu không, hãy xem xét sử dụng phiên bản không đồng bộ của hàm để tránh chặn vòng lặp sự kiện. (Một thư viện hứa hẹn như bluebirdlà hữu ích).

Cập nhật vào 23-JAN-2019

Lỗi trong logic giải thuật đã được sửa. Cảm ơn @ AlexisWilke đã chỉ ra điều đó một cách đúng mực .Câu vấn đáp được đồng ý là 7 năm tuổi và thời nay có vẻ như không được bảo vệ. Do đó, tôi đang vấn đáp nó :

  1. Thuật toán mã hóa : Mật mã khối AES với khóa 256 bit được coi là đủ an toàn. Để mã hóa một tin nhắn hoàn chỉnh, cần phải chọn một chế độ. Nên sử dụng mã hóa đã xác thực (cung cấp cả tính bảo mật và tính toàn vẹn). GCM, CCM và EAX là các chế độ mã hóa đã xác thực được sử dụng phổ biến nhất. GCM thường được ưu tiên hơn và nó hoạt động tốt trong các kiến ​​trúc của Intel, nơi cung cấp các hướng dẫn dành riêng cho GCM. Tất cả ba chế độ này đều là chế độ dựa trên CTR (dựa trên bộ đếm) và do đó chúng không cần đệm. Do đó, chúng không dễ bị tấn công bởi các cuộc tấn công liên quan đến đệm

  2. Véc tơ khởi tạo (IV) là bắt buộc đối với GCM. IV không phải là một bí mật. Yêu cầu duy nhất là nó phải ngẫu nhiên hoặc không thể đoán trước. Trong NodeJs, crypto.randomBytes()có nghĩa là tạo ra các số ngẫu nhiên giả mạnh về mặt mật mã.

  3. NIST yêu cầu 96 bit IV cho GCM để thôi thúc năng lực tương tác, hiệu suất cao và tính đơn thuần của phong cách thiết kế
  4. Người nhận cần biết IV để hoàn toàn có thể giải thuật văn bản mật mã. Do đó IV cần được chuyển cùng với văn bản mật mã. Một số tiến hành gửi IV dưới dạng AD ( Dữ liệu được link ) có nghĩa là thẻ xác nhận sẽ được thống kê giám sát trên cả văn bản mật mã và IV. Tuy nhiên, điều đó là không bắt buộc. IV hoàn toàn có thể chỉ đơn thuần là chờ trước với văn bản mật mã chính do nếu IV bị biến hóa trong quy trình truyền do một cuộc tiến công có chủ ý hoặc lỗi mạng lưới hệ thống mạng / tệp, việc xác nhận thẻ xác nhận sẽ không thành công xuất sắc .
  5. Các chuỗi không nên được sử dụng để giữ tin nhắn văn bản rõ ràng, mật khẩu hoặc khóa vì Chuỗi là bất biến, có nghĩa là chúng ta không thể xóa các chuỗi sau khi sử dụng và chúng sẽ lưu lại trong bộ nhớ. Do đó, một kết xuất bộ nhớ có thể tiết lộ thông tin nhạy cảm. Vì lý do tương tự, ứng dụng khách gọi các phương thức mã hóa hoặc giải mã này sẽ xóa tất cả việc Buffergiữ tin nhắn, khóa hoặc mật khẩu sau khi không còn cần sử dụng bufferVal.fill(0)nữa.

  6. Cuối cùng để truyền qua mạng hoặc lưu trữ, văn bản mật mã phải được mã hóa bằng cách sử dụng mã hóa Base64. buffer.toString('base64');có thể được sử dụng để chuyển đổi Bufferthành chuỗi được mã hóa Base64.

  7. Lưu ý rằng scrypt ( crypto.scryptSync()) dẫn xuất khóa đã được sử dụng để lấy khóa từ mật khẩu. Tuy nhiên, chức năng này chỉ khả dụng trong Node 10. * và các phiên bản mới hơn

Mã ở đây :

const crypto = require('crypto');

var exports = module.exports = {};

const ALGORITHM = {
    
    /**
     * GCM is an authenticated encryption mode that
     * not only provides confidentiality but also 
     * provides integrity in a secured way
     * */  
    BLOCK_CIPHER: 'aes-256-gcm',

    /**
     * 128 bit auth tag is recommended for GCM
     */
    AUTH_TAG_BYTE_LEN: 16,

    /**
     * NIST recommends 96 bits or 12 bytes IV for GCM
     * to promote interoperability, efficiency, and
     * simplicity of design
     */
    IV_BYTE_LEN: 12,

    /**
     * Note: 256 (in algorithm name) is key size. 
     * Block size for AES is always 128
     */
    KEY_BYTE_LEN: 32,

    /**
     * To prevent rainbow table attacks
     * */
    SALT_BYTE_LEN: 16
}

const getIV = () => crypto.randomBytes(ALGORITHM.IV_BYTE_LEN);
exports.getRandomKey = getRandomKey = () => crypto.randomBytes(ALGORITHM.KEY_BYTE_LEN);

/**
 * To prevent rainbow table attacks
 * */
exports.getSalt = getSalt = () => crypto.randomBytes(ALGORITHM.SALT_BYTE_LEN);

/**
 * 
 * @param {Buffer} password - The password to be used for generating key
 * 
 * To be used when key needs to be generated based on password.
 * The caller of this function has the responsibility to clear 
 * the Buffer after the key generation to prevent the password 
 * from lingering in the memory
 */
exports.getKeyFromPassword = getKeyFromPassword = (password, salt) => {
    return crypto.scryptSync(password, salt, ALGORITHM.KEY_BYTE_LEN);
}

/**
 * 
 * @param {Buffer} messagetext - The clear text message to be encrypted
 * @param {Buffer} key - The key to be used for encryption
 * 
 * The caller of this function has the responsibility to clear 
 * the Buffer after the encryption to prevent the message text 
 * and the key from lingering in the memory
 */
exports.encrypt = encrypt = (messagetext, key) => {
    const iv = getIV();
    const cipher = crypto.createCipheriv(
        ALGORITHM.BLOCK_CIPHER, key, iv,
        { 'authTagLength': ALGORITHM.AUTH_TAG_BYTE_LEN });
    let encryptedMessage = cipher.update(messagetext);
    encryptedMessage = Buffer.concat([encryptedMessage, cipher.final()]);
    return Buffer.concat([iv, encryptedMessage, cipher.getAuthTag()]);
}

/**
 * 
 * @param {Buffer} ciphertext - Cipher text
 * @param {Buffer} key - The key to be used for decryption
 * 
 * The caller of this function has the responsibility to clear 
 * the Buffer after the decryption to prevent the message text 
 * and the key from lingering in the memory
 */
exports.decrypt = decrypt = (ciphertext, key) => {
    const authTag = ciphertext.slice(-16);
    const iv = ciphertext.slice(0, 12);
    const encryptedMessage = ciphertext.slice(12, -16);
    const decipher = crypto.createDecipheriv(
        ALGORITHM.BLOCK_CIPHER, key, iv,
        { 'authTagLength': ALGORITHM.AUTH_TAG_BYTE_LEN });
    decipher.setAuthTag(authTag);
    let messagetext = decipher.update(encryptedMessage);
    messagetext = Buffer.concat([messagetext, decipher.final()]);
    return messagetext;
}

Và những bài kiểm tra đơn vị chức năng cũng được phân phối bên dưới :

const assert = require('assert');
const cryptoUtils = require('../lib/crypto_utils');
describe('CryptoUtils', function() {
  describe('decrypt()', function() {
    it('should return the same mesage text after decryption of text encrypted with a '
     + 'randomly generated key', function() {
      let plaintext = 'my message text';
      let key = cryptoUtils.getRandomKey();
      let ciphertext = cryptoUtils.encrypt(plaintext, key);

      let decryptOutput = cryptoUtils.decrypt(ciphertext, key);

      assert.equal(decryptOutput.toString('utf8'), plaintext);
    });

    it('should return the same mesage text after decryption of text excrypted with a '
     + 'key generated from a password', function() {
      let plaintext = 'my message text';
      /**
       * Ideally the password would be read from a file and will be in a Buffer
       */
      let key = cryptoUtils.getKeyFromPassword(
              Buffer.from('mysecretpassword'), cryptoUtils.getSalt());
      let ciphertext = cryptoUtils.encrypt(plaintext, key);

      let decryptOutput = cryptoUtils.decrypt(ciphertext, key);

      assert.equal(decryptOutput.toString('utf8'), plaintext);
    });
  });
});

Source: https://trade.edu.vn
Category: Blockchain

Vote sao

Trả lời

Email của bạn sẽ không được hiển thị công khai.