Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/189.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Node.js加密模块加密,使用Java解密(在Android应用程序中)_Java_Android_Node.js_Cryptography - Fatal编程技术网

使用Node.js加密模块加密,使用Java解密(在Android应用程序中)

使用Node.js加密模块加密,使用Java解密(在Android应用程序中),java,android,node.js,cryptography,Java,Android,Node.js,Cryptography,正在寻找一种在节点中加密数据(主要是字符串)并在android应用程序(java)中解密的方法 在每个节点中都成功地完成了加密/解密(在节点中加密/解密,在java中加密/解密),但似乎无法在它们之间工作 可能我没有用同样的方式加密/解密,但每种语言中的每个库对相同的东西都有不同的名称 谢谢你的帮助 下面是一些代码: Node.js 和爪哇 private static String decrypt(byte[] raw, byte[] encrypted) throws Exception {

正在寻找一种在节点中加密数据(主要是字符串)并在android应用程序(java)中解密的方法

在每个节点中都成功地完成了加密/解密(在节点中加密/解密,在java中加密/解密),但似乎无法在它们之间工作

可能我没有用同样的方式加密/解密,但每种语言中的每个库对相同的东西都有不同的名称

谢谢你的帮助

下面是一些代码: Node.js

和爪哇

private static String decrypt(byte[] raw, byte[] encrypted) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec );
    byte[] decrypted = cipher.doFinal(encrypted);
    return new String(decrypted);
}
原始密钥是这样创建的

private static byte[] getRawKey(String seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    byte[] seedBytes = seed.getBytes()
    sr.setSeed(seedBytes);
    kgen.init(128, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}
public static byte[] toByte(String hexString) {
    int len = hexString.length()/2;
    byte[] result = new byte[len];
    for (int i = 0; i < len; i++)
        result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
    return result;
}
而加密的十六进制字符串被转换成如下字节

private static byte[] getRawKey(String seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    byte[] seedBytes = seed.getBytes()
    sr.setSeed(seedBytes);
    kgen.init(128, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}
public static byte[] toByte(String hexString) {
    int len = hexString.length()/2;
    byte[] result = new byte[len];
    for (int i = 0; i < len; i++)
        result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
    return result;
}
公共静态字节[]toByte(字符串hexString){
int len=hexString.length()/2;
字节[]结果=新字节[len];
对于(int i=0;i
您需要确保正在使用

  • 同一把钥匙
  • 相同的算法、操作模式和填充
在连接的两侧

对于,在Java端,您使用了相当多的工作来从字符串派生键-在node.js端没有这样做。在这里使用标准的密钥派生算法(两边都使用相同的算法)

再看一遍,这条线

var cipher = crypto.createCipher('aes-128-cbc','somepass')
确实进行了一些关键推导,只是:

crypto.createCipher(算法、密码)

使用给定的算法和密码创建并返回密码对象

算法
依赖于OpenSSL,例如
'aes192'
等。在最新版本中,
OpenSSL列表密码算法
将显示可用的密码算法
password
用于派生密钥和IV,它们必须是
'binary'
编码的 字符串(有关详细信息,请参阅)

好的,这至少说明了如何对其进行编码,但不是这里要做什么。因此,我们可以使用另一种初始化方法(直接获取键和初始化向量,不做任何修改就使用它们),也可以查看源代码

<>代码> CurtCeCiffe<代码>将在NoDEIONFROC.CC中以某种方式调用C++函数。本质上,它使用
EVP_BytesToKey
函数从提供的字符串(使用MD5、空salt和count 1)派生密钥,然后执行与
cipheritiv
相同的操作(由
createCipheriv
调用,并直接使用IV和key)

由于AES使用128位的密钥和初始化向量,而MD5有128位的输出,这实际上意味着

key = MD5(password)
iv = MD5(key + password)
(其中+表示串联,而不是加法)。如果需要,可以使用MessageDigest类在Java中重新实现这个密钥派生

更好的办法是使用一些缓慢的密钥派生算法,特别是如果你的密码是人类可以记住的。然后在node.js端使用函数生成此密钥,在Java端使用PBEKeySpec和SecretKeyFactory(使用算法
PBKDF2WithHmacSHA1
)生成此密钥。(选择一个迭代次数,它不会让您的客户抱怨最常见设备的运行缓慢。)

对于您的密码算法,在Java端,您说的是“将AES算法与缺省操作模式和缺省填充模式一起使用”。不要这样做,因为它可能会随着提供者的不同而变化

相反,使用操作模式的明确指示(
CBC
,在您的情况下),以及填充模式的明确指示。一个例子可能是:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
请查看node.js文档,了解如何在其中指示填充模式(或者默认为哪一种,以便在Java端选择相同的填充模式)。(从中,看起来默认值也是PKCS5P添加到此处。)


此外,不要自己实现加密,而是考虑使用TLS进行传输加密。(当然,这只在双方都有实时连接的情况下才有效。)

显然,如果将密码短语传递给
crypto.createCipher()
它将使用OpenSSL的
EVP\u BytesToKey()
来派生密钥。您可以传递原始字节缓冲区并使用它初始化Java的
SecretKey
,或者在Java代码中模拟
EVP\u BytesToKey()
。使用
$man EVP_BytesToKey
了解更多详细信息,但本质上它使用MD5多次散列密码短语并连接salt

至于使用原始密钥,类似这样的东西应该允许您使用原始密钥:

var c=crypto.createCipheriv(“aes-128-ecb”,新缓冲区(“0001020305060708A0B0C0D0F101112”,“十六进制”)。toString(“二进制”),“”)

请注意,由于您使用的是CBC,因此需要使用相同的IV进行加密和解密(您可能希望将其附加到消息中,等等)


强制性警告:自己实现加密协议很少是个好主意。即使你能做到这一点,你会对所有消息使用相同的密钥吗?要多久?如果决定旋转关键点,请说明如何进行管理。等等等等等等

谢谢大家。你的回答和评论为我指明了正确的方向,通过进一步的研究,我成功地得到了一个工作原型(粘贴在下面)。 事实证明,节点的加密使用MD5对密钥进行散列,而填充显然是使用PKCS7Padding完成的(通过反复试验得到的)

至于首先要做这件事的原因: 我的申请由三部分组成: A.后端服务 B.第三方数据存储 C.作为客户端的android应用程序

后端服务准备数据并将其发布给第三方。 android应用程序获取和/或更新数据存储中的数据,该服务可能会根据这些数据进行操作

加密的需要是保持数据的私密性,即使来自第三方提供商

至于密钥管理,我想我可以让服务器创建一个新的密钥e
public static String decrypt(String seed, String encrypted) throws Exception {
  byte[] keyb = seed.getBytes("UTF-8");
  MessageDigest md = MessageDigest.getInstance("MD5");
  byte[] thedigest = md.digest(keyb);
  SecretKeySpec skey = new SecretKeySpec(thedigest, "AES/ECB/PKCS7Padding");
  Cipher dcipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
  dcipher.init(Cipher.DECRYPT_MODE, skey);

  byte[] clearbyte = dcipher.doFinal(toByte(encrypted));
  return new String(clearbyte);
}

public static byte[] toByte(String hexString) {
  int len = hexString.length()/2;
  byte[] result = new byte[len];
  for (int i = 0; i < len; i++)
    result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
  return result;
}
var crypto = require('crypto')
var cipher = crypto.createCipher('aes-128-ecb','somepassword')
var text = "the big brown fox jumped over the fence"
var crypted = cipher.update(text,'utf-8','hex')
crypted += cipher.final('hex')
//now crypted contains the hex representation of the ciphertext
private static String decrypt(String seed, String encrypted) throws Exception {
    byte[] keyb = seed.getBytes("UTF-8");
    MessageDigest md = MessageDigest.getInstance("MD5");
    byte[] thedigest = md.digest(keyb);
    SecretKeySpec skey = new SecretKeySpec(thedigest, "AES");
    Cipher dcipher = Cipher.getInstance("AES");
    dcipher.init(Cipher.DECRYPT_MODE, skey);

    byte[] clearbyte = dcipher.doFinal(toByte(encrypted));
    return new String(clearbyte);
}

private static byte[] toByte(String hexString) {
    int len = hexString.length()/2;
    byte[] result = new byte[len];
    for (int i = 0; i < len; i++) {
        result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
    }
    return result;
}