Nodejs 之 分享加密算法

{app.params.name}} {app.params.name}} {app.params.name}}

这里分享一个node实现的加解密算法,唉,对接了至少三家的接口但是没加的算法都不一样。看着做为程序员的辛苦,我这里分享了。

/**
 * @author zhandapeng <896360979@qq.com>
 * @date 7/12/2016
 *
 * openssl pkcs12 -in 9f_KDJZ_private.pfx -out 9f_KDJZ_private.pem -nodes   
 * openssl x509 -in 9fwlc_public.crt -outform der -out 9fwlc_public.der
 * openssl x509 -in 9fwlc_public.crt -inform der -outform pem -out 9fwlc_public.pem
 *
 * 玖富加密解密
 */
'use strict';

const crypto = require('crypto');
const constants = require('constants');
const _padding = constants.RSA_PKCS1_PADDING;
const _encoding = 'base64';
const _signatureAlgorithm = 'RSA-SHA1';


class XxxxRSA {
  constructor(options) {
    this.options = Object.assign({}, options);
  }

  /**
   * 签名
   * @param  {String} data [加密的数据]
   * @return {String}      [签名的数据]
   */
  _sign(data) {
    const sign = crypto.createSign(_signatureAlgorithm);
    sign.update(data, 'utf8');
    return sign.sign(this.options.privateKey, _encoding);
  }

  /**
   * 验签
   * @param  {String} sign [签名数据]
   * @param  {String} data [加密数据]
   * @return {Boolean}      [description]
   */
  _verify(sign, data) {
    const verifier = crypto.createVerify(_signatureAlgorithm);
    verifier.update(new Buffer(data, _encoding), 'utf8');
    return verifier.verify(this.options.publicKey, new Buffer(sign, _encoding));
  }

  /**
   * 加密
   * @param  {String} msg [要加密的数据]
   * @return {Object}     [签名的数据和加密的数据]
   */
  encrypt(msg) {
    const blockSize = 128;
    const padding = 11;

    let buffer = new Buffer(msg);

    const chunkSize = blockSize - padding;
    const nbBlocks = Math.ceil(buffer.length / (chunkSize));

    let outputBuffer = new Buffer(nbBlocks * blockSize);
    for (let i = 0; i < nbBlocks; i++) {
      let currentBlock = buffer.slice(chunkSize * i, chunkSize * (i + 1));
      let encryptedChunk = crypto.publicEncrypt({
        key: this.options.publicKey,
        padding: _padding
      }, currentBlock);

      encryptedChunk.copy(outputBuffer, i * blockSize);
    }

    return {
      data: outputBuffer.toString(_encoding),
      sign: this._sign(outputBuffer)
    };
  };

  /**
   * 解密
   * @param  {Object} obj [签名数据和加密数据]
   * @return {String}     [解密的数据]
   */
  decrypt(obj) {
    if (!this._verify(obj.sign, obj.data)) {
      throw new Error('Sign verify field.');
    }

    const blockSize = 128;
    let buffer = new Buffer(obj.data, _encoding);
    const nbBlocks = Math.ceil(buffer.length / (blockSize));
    let outputBuffer = new Buffer(nbBlocks * blockSize);

    let totalLength = 0;
    for (var i = 0; i < nbBlocks; i++) {
      let currentBlock = buffer.slice(blockSize * i, Math.min(blockSize * (i + 1), buffer.length));
      let decryptedBuf = crypto.privateDecrypt({
        key: this.options.privateKey,
        padding: _padding
      }, currentBlock);

      decryptedBuf.copy(outputBuffer, totalLength);
      totalLength += decryptedBuf.length;
    }

    let data = outputBuffer.slice(0, totalLength);

    return data.toString();
  };
}

export default XxxxRSA;

事实上简单的不得了,只是我不会而已,对不起献丑了。

这里针对java和php版本做个参考。主要是是说encrypt和decrypt部分。

encrypt->java实现

public static String encrypt(Key key, String dataStr)
        throws RuntimeException {
    try {
        byte[] data = dataStr.getBytes("UTF-8");
        Cipher cipher = Cipher.getInstance(transformation);
        cipher.init(Cipher.ENCRYPT_MODE, key);

        int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
        int leavedSize = data.length % MAX_ENCRYPT_BLOCK;
        int blocksSize = leavedSize != 0 ? data.length / MAX_ENCRYPT_BLOCK
                + 1 : data.length / MAX_ENCRYPT_BLOCK;
        byte[] raw = new byte[outputSize * blocksSize];
        int i = 0;
        while (data.length - i * MAX_ENCRYPT_BLOCK > 0) {
            if (data.length - i * MAX_ENCRYPT_BLOCK > MAX_ENCRYPT_BLOCK)
                cipher.doFinal(data, i * MAX_ENCRYPT_BLOCK,
                        MAX_ENCRYPT_BLOCK, raw, i * outputSize);
            else
                cipher.doFinal(data, i * MAX_ENCRYPT_BLOCK, data.length - i
                        * MAX_ENCRYPT_BLOCK, raw, i * outputSize);
            i++;
        }
        return Base64.encodeBase64String(raw);

    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    } catch (NoSuchPaddingException e) {
        throw new RuntimeException(e);
    } catch (IllegalBlockSizeException e) {
        throw new RuntimeException(e);
    } catch (BadPaddingException e) {
        throw new RuntimeException(e);
    } catch (InvalidKeyException e) {
        throw new RuntimeException(e);
    } catch (ShortBufferException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}

decrypt->java实现

public static String decrypt(Key key, String dataStr)
        throws RuntimeException {
    try {
        byte[] data = Base64.decodeBase64(dataStr);
        Cipher cipher = Cipher.getInstance(transformation);
        cipher.init(Cipher.DECRYPT_MODE, key);
        ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
        int j = 0;

        while (data.length - j * MAX_DECRYPT_BLOCK > 0) {
            bout.write(cipher.doFinal(data, j * MAX_DECRYPT_BLOCK,
                    MAX_DECRYPT_BLOCK));
            j++;
        }
        return new String(bout.toByteArray(), "UTF-8");
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    } catch (NoSuchPaddingException e) {
        throw new RuntimeException(e);
    } catch (InvalidKeyException e) {
        throw new RuntimeException(e);
    } catch (IllegalBlockSizeException e) {
        throw new RuntimeException(e);
    } catch (BadPaddingException e) {
        throw new RuntimeException(e);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

encrypt->php实现

public function encrypt($content, $public_key) {
    $priKey = file_get_contents($public_key);
    $res = openssl_get_publickey($priKey);
    //把需要加密的内容,按128位拆开加密
    $result  = '';
    for($i = 0; $i < ((strlen($content) - strlen($content)%117)/117+1); $i++  ) {
        $data = mb_strcut($content, $i*117, 117, 'utf-8');
        openssl_public_encrypt($data, $encrypted, $res);
        $result .= $encrypted;
    }
    openssl_free_key($res);
    //用base64将二进制编码
    $result = base64_encode($result);
    return $result;
}

decrypt->php实现

public function rsaDecrypt($content, $private_key) {
    $priKey = file_get_contents($private_key);
    $res = openssl_get_privatekey($priKey);
    // var_dump($priKey);
    // var_dump($res);exit();
    //用base64将内容还原成二进制
    $content = base64_decode($content);
    //把需要解密的内容,按128位拆开解密
    $result  = '';
    for($i = 0; $i < strlen($content)/128; $i++  ) {
        $data = substr($content, $i * 128, 128);
        openssl_private_decrypt($data, $decrypt, $res);
        $result .= $decrypt;
    }
    openssl_free_key($res);
    return $result;
}

好了 写了这些,做个记录。也不知道是不是违法的,希望别举报我。


版权声明

durban 创作并维护的 Gowhich 博客采用 创作共用保留署名-非商业-禁止演绎4.0国际许可证。

本文首发于 Gowhich 博客( https://www.gowhich.com ),版权所有,侵权必究。

本文永久链接: https://www.gowhich.com/blog/755

comments powered by Disqus