zoukankan      html  css  js  c++  java
  • node.js 实现 AES CTR 加解密

    node.js 实现 AES CTR 加解密

    前言

    由于最近我们在做一款安全的文件分享 App, 所有文件均需要使用 aes ctr 来进行加密,aes key 还有一整套完整的许可体系在保护, 然后再通知各种阅读器进行打开。

    关于 aes ctr 不在此做说明,如需了解,请访问 : AES CTR 详细介绍

    正文

    直接上代码

    'use strict'
    
    var crypto = require('crypto')
    
    // 异或 key 的加解算法
    let alg = 'aes-256-ecb';
    // 加密的数据块大小,单位字节
    let block_size  = 16;
    
    class AES {
        /**
         * 构造函数
         * @param key_buffer  aes key 的 byte 数组
         * @param iv_buffer   随机数据的 byte 数组
         */
        constructor(key_buffer,iv_buffer ){
            this._key = key_buffer;
            this._iv = iv_buffer;
        }
    
        /**
         * 加密
         * @param data_buffer  明文数据
         * @param offset       偏移量
         * @returns {Buffer}   加密后的数据
         */
        encryt(data_buffer, offset ){
            return this._crypt(data_buffer, offset)
        }
    
        /**
         * 解密
         * @param enc_data_buffer 加密后的数据
         * @param offset          偏移量
         * @returns {Buffer}      解密后的数据
         */
        decrypt(enc_data_buffer, offset){
           return this._crypt(enc_data_buffer, offset);
        }
    
        /**
         * 加解密传的数据块
         * @param data_buffer     数据 buffer
         * @param offset          偏移量,用于计算 counter
         * @returns {Buffer}      加密或解密后的数据
         * @private
         */
        _crypt(data_buffer, offset){
    
            let byte_length = data_buffer.length;
            let enc_data_buffer = Buffer.alloc(byte_length);
    
            let start_counter = Math.floor(offset / block_size);
            let total_counter = (offset+byte_length) % block_size == 0 ?
                                                                ((offset+byte_length) / block_size)-1 :
                                                                Math.floor((offset+byte_length) / block_size);
            // 已处理的字节长度
            var handled_length = 0;
            for(var i = start_counter; i<= total_counter; i++){
                // 本次处理的字节长度
                let handle_length = (i+1)*block_size-offset-handled_length;
                if(handled_length + handle_length > byte_length){
                    handle_length = byte_length - handled_length;
                }
                let handle_data_buffer = data_buffer.slice(handled_length, handled_length + handle_length);
                let handled_data_buffer = null;
                if(i == 0 && handle_length < block_size && total_counter > 0){
                    handled_data_buffer = this._cryptBlock(handle_data_buffer, i, handle_length,-1);
                } else {
                    handled_data_buffer = this._cryptBlock(handle_data_buffer, i, handle_length,0);
                }
    
                enc_data_buffer.fill(handled_data_buffer,handled_length, handled_length+handle_length);
                handled_length += handle_length;
    
            }
    
            return enc_data_buffer;
        }
    
        /**
         * 对16个字节的数据块的加解密
         * @param data_buffer  要加密的16字节数据块
         * @param counter      分块代号,从0开始
         * @param length       data_buffer 的长度,<=16, 多数情况下为 16,只有在不满 16 字节时才会 < 16
         * @param forward -1:  表示数据块头不足 16 字节,0 表示正好是 16 字节 或 数据块尾不满 16 节节
         * @returns {Buffer}
         * @private
         */
        _cryptBlock(data_buffer, counter, length, forward){
    
            var xor_buffer = Buffer.alloc(block_size);
            xor_buffer.fill(this._iv.slice(0,8),0,8)
            xor_buffer.writeUIntBE(counter,10,6);
    
            let cipher = crypto.createCipheriv(alg,this._key,null);
            var xor_key_buffer = cipher.update(xor_buffer);
            cipher.final();
    
            var enc_buffer = Buffer.alloc(length);
            if(forward === -1){
                let length_diff = block_size - length;
                for(var i=length_diff;i<block_size;i++){
                    let number = data_buffer[i-length_diff] ^ xor_key_buffer[i];
                    enc_buffer[i-length_diff] = number;
                }
            } else {
                for(var i =0; i < length; i++){
                    let number = data_buffer[i] ^ xor_key_buffer[i];
                    enc_buffer[i] = number;
                }
            }
            return enc_buffer;
        }
    }
    
    
    exports.AES = AES;
    

     

     

  • 相关阅读:
    sharepoint部署
    继承实体类出现传值时值不能保留
    面试经历
    sharepoint更换数据库链接
    asp.net c# 打开新页面或页面跳转
    sharepoint中配置工作流
    AD添加组织单位
    常用正则表达式
    删除多级非空目录
    C#实现对Word文件读写
  • 原文地址:https://www.cnblogs.com/feshfans/p/11001523.html
Copyright © 2011-2022 走看看