首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Node.js中的AES加密和Java Android中的解密

Node.js中的AES加密和Java Android中的解密
EN

Stack Overflow用户
提问于 2018-09-13 07:33:21
回答 1查看 758关注 0票数 -1

我使用ricmoo/aes-js来加密节点服务器响应,

Cypher.js

代码语言:javascript
复制
"use strict";

var aesjs = require("aes-js");
var sha256 = require("js-sha256");

const getKeyArray = function() {
  let buffer = sha256.arrayBuffer("mykey");
  let keyArray = new Uint8Array(buffer);
  const keySize = 16;
  let arr = new Array();
  for (var i = 0; i < keySize; i++) {
    arr.push(keyArray[i]);
  }
  return arr;
};

module.exports = {
  getKey: function() {
    return getKeyArray();
  },

  encrypt: function(text) {
    var textBytes = aesjs.utils.utf8.toBytes(text);

    // The counter is optional, and if omitted will begin at 1
    var aesCtr = new aesjs.ModeOfOperation.ctr(
      getKeyArray(),
      new aesjs.Counter(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))
    );

    var counterArray = aesCtr._counter._counter.slice()

    var encryptedBytes = aesCtr.encrypt(textBytes);

    // To print or store the binary data, you may convert it to hex
    var encryptedHex = aesjs.utils.hex.fromBytes(encryptedBytes);

    var ivHex = aesjs.utils.hex.fromBytes(counterArray);

    return ivHex + ":" + encryptedHex;
  },
  decrypt: function(encryptedHex) {
    let split = encryptedHex.split(":");

    // When ready to decrypt the hex string, convert it back to bytes
    var encryptedBytes = aesjs.utils.hex.toBytes(split[1]);

    let ivHex = split[0];

    var ivBytes = aesjs.utils.hex.toBytes(ivHex);

    var counter = new aesjs.Counter(ivBytes);

    // The counter mode of operation maintains internal state, so to
    // decrypt a new instance must be instantiated.
    var aesCtr = new aesjs.ModeOfOperation.ctr(getKeyArray(), ivBytes);

    var decryptedBytes = aesCtr.decrypt(encryptedBytes);

    // Convert our bytes back into text
    var decryptedText = aesjs.utils.utf8.fromBytes(decryptedBytes);

    return decryptedText;
  }
};

和Java中的解密

Cypher.java

代码语言:javascript
复制
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

class Cypher {
    private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

    private static String KEY = "mykey";

    /**
     * Decrypt a given hex string,
     * @param hexString
     * @return
     */
    static String decrypt(String hexString) throws Exception{
        Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

        String ivHex = hexString.split(":")[0];
        hexString = hexString.split(":")[1];

        IvParameterSpec ivSpec = new IvParameterSpec(hexStringToByteArray(ivHex));

        cipher.init(Cipher.DECRYPT_MODE, getEncryptionKey(KEY), ivSpec);

        byte[] decrypted = cipher.doFinal(hexStringToByteArray(hexString));

        return new String(decrypted);
    }

    private static SecretKeySpec getEncryptionKey(String key) throws Exception {

        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(key.getBytes("UTF-8"));
        byte[] keyBytes = new byte[16];
        System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        return secretKeySpec;

    }

    static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
}

我的问题是:

1-上面的代码是否可以接受,或者它有什么主要问题?

2-我如何改进它?

EN

回答 1

Stack Overflow用户

发布于 2018-09-13 07:33:21

编辑2

我已经更新了问题,现在有问题的代码在加密和解密过程中使用随机IV。

编辑

请不要使用下面的代码,因为它不会随机生成IV,请参阅下面的注释。

旧答案

这并不容易,但我终于让它工作了,这是我的完整工作代码( node.js上的加密和安卓上的解密):

Cypher.js

代码语言:javascript
复制
"use strict";

var aesjs = require("aes-js");
var sha256 = require("js-sha256");

const getKeyArray = function() { // decryption on Android doesn't support 256 bit keys with AES/CTR, so I'm using only 128 bits
  let buffer = sha256.arrayBuffer("mystrongkey");
  let keyArray =  new Uint8Array(buffer);
  const keySize = 16;
  let arr = new Array;
  for (var i = 0; i < keySize; i++) {
    arr.push(keyArray[i]);
  }
  return arr;
}

module.exports = {
  getKey: function() {
    return getKeyArray();
  },
  getIV: function() {
    return new aesjs.Counter(5);
  },
  encrypt: function(text) {
    var textBytes = aesjs.utils.utf8.toBytes(text);

    // The counter is optional, and if omitted will begin at 1
    var aesCtr = new aesjs.ModeOfOperation.ctr(getKeyArray(), this.getIV());
    var encryptedBytes = aesCtr.encrypt(textBytes);

    // To print or store the binary data, you may convert it to hex
    var encryptedHex = aesjs.utils.hex.fromBytes(encryptedBytes);
    return encryptedHex;
  },
  decrypt: function(encryptedHex) {
    // When ready to decrypt the hex string, convert it back to bytes
    var encryptedBytes = aesjs.utils.hex.toBytes(encryptedHex);

    // The counter mode of operation maintains internal state, so to
    // decrypt a new instance must be instantiated.
    var aesCtr = new aesjs.ModeOfOperation.ctr(getKeyArray(), this.getIV());
    var decryptedBytes = aesCtr.decrypt(encryptedBytes);

    // Convert our bytes back into text
    var decryptedText = aesjs.utils.utf8.fromBytes(decryptedBytes);
    return decryptedText;
  }
};

Cypher.java

代码语言:javascript
复制
package com.mypackage;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

class Cypher {
    private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

    private static String KEY = "mystrongkey";

    /**
     * Decrypt a given hex string,
     * 08768efebc = Hello
     * @param hexString
     * @return
     */
    static String decrypt(String hexString) throws Exception{
        Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

        IvParameterSpec ivSpec = new IvParameterSpec(new byte[] { // got this one by console.log(Cypher.getIv()) from Cypher.js
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                5
        });

        cipher.init(Cipher.DECRYPT_MODE, getEncryptionKey(KEY), ivSpec);

        byte[] decrypted = cipher.doFinal(hexStringToByteArray(hexString));

        return new String(decrypted);
    }

    static String encrypt(String string) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

        IvParameterSpec ivSpec = new IvParameterSpec(new byte[] {
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                5
        });

        cipher.init(Cipher.ENCRYPT_MODE, getEncryptionKey(KEY), ivSpec);

        byte[] encrypted = cipher.doFinal(string.getBytes());

        return bytesToHex(encrypted);
    }

    private static SecretKeySpec getEncryptionKey(String key) throws Exception {

        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(key.getBytes("UTF-8"));
        byte[] keyBytes = new byte[16];
        System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        return secretKeySpec;

    }

    static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
}

我希望这将节省一些人试图从node.js解密的时间

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52304774

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档