Nodejs加密的字符串与java不匹配:AES-256-CBC

时间:2017-09-14 05:45:48

标签: java node.js encryption

您好我已经使用相同的算法编写了nodejs加密和Java加密。但是Java和NodeJS正在返回不同的加密字符串。请帮帮我。

//这是我的Java代码

import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;

    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.util.Base64;

    public enum AESUtil {
        ;
        private static final String ENCRYPTION_KEY = "RwcmlVpg";
        private static final String ENCRYPTION_IV = "4e5Wa71fYoT7MFEX";

        public static String encrypt(String src) {
            try {
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, makeKey(), makeIv());
                Base64.Encoder encoder = Base64.getEncoder();
                return encoder.encodeToString(cipher.doFinal(src.getBytes()));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        public static String decrypt(String src) {
            String decrypted = "";
            try {
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(Cipher.DECRYPT_MODE, makeKey(), makeIv());
                Base64.Decoder decoder = Base64.getDecoder();
                decrypted = new String(cipher.doFinal(decoder.decode(src)));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return decrypted;
        }

        static AlgorithmParameterSpec makeIv() {
            try {
                return new IvParameterSpec(ENCRYPTION_IV.getBytes("UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return null;
        }

        static Key makeKey() {
            try {
                MessageDigest md = MessageDigest.getInstance("SHA-256");
                byte[] key = md.digest(ENCRYPTION_KEY.getBytes("UTF-8"));
                return new SecretKeySpec(key, "AES");
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            return null;
        }
    }

//下面是测试上面代码的代码

    public class AESMain {

        /**
         * @param args
         */
        public static void main(String[] args) {
            String src = "Hello,CryptWorld";
            String encrypted = AESUtil.encrypt(src);
            String decrypted = AESUtil.decrypt(encrypted);
            System.out.println("src: " + src);
            System.out.println("encrypted: " + encrypted);
            System.out.println("decrypted: " + decrypted);
        }

    }

以上代码的回复是

src: Hello,CryptWorld
encrypted: rh7ro9NH1XZeLX95paLETDgYxRbnDoOIrxarO0Sy73s=
decrypted: Hello,CryptWorld

//节点JS代码

var Encrypt, crypto;

crypto = require("crypto");


Encrypt = module.exports = (function() {
  var b64dec, b64enc, cipher, decrypt, encrypt, iv, key;
  key = crypto.createHash("sha256").update("RwcmlVpg").digest();
  iv = '4e5Wa71fYoT7MFEX';
  cipher = function(mode, data) {
    var encipher, encoded;
    encipher = crypto[mode]("aes-256-cbc", key, iv);
    encoded = encipher.update(data);
    encoded += encipher.final();
    return encoded;
  };
  encrypt = function(data) {
    return b64enc(cipher("createCipheriv", data));
  };
  decrypt = function(data) {
    return cipher("createDecipheriv", b64dec(data));
  };
  b64enc = function(data) {
    var b;
    b = new Buffer(data, "binary");
    return b.toString("base64");
  };
  b64dec = function(data) {
    var b;
    b = new Buffer(data, "base64");
    return b.toString("binary");
  };
  return {
    encrypt: encrypt,
    decrypt: decrypt
  };
})();
var expected = Encrypt.encrypt("Hello,CryptWorld");
console.log("expected " + expected);

来自Node JS的响应是

expected /R79/f1H/XZeLX95/f39TDgY/Rb9Dv39/Rb9O0T9/Xs=

节点js版本为v6.10.1,JDK版本为1.8.0_77。

我真的不知道我错过了什么。

2 个答案:

答案 0 :(得分:0)

我的第一个提示是确保你完全相同:

  1. 字符编码
  2. 行结尾
  3. 在两个程序中,用于加密的文本和密钥。尝试将文本缓冲区和密钥打印为十六进制,并在进行任何加密之前对其进行比较。如果他们不同,那么你的问题就出现了。如果它们相同,则加密本身可能存在问题。

    请注意,默认情况下,Node使用UTF-8,而Java据我所知在内部使用UCS-2。我看到你正在尝试转换编码,但是在加密步骤之前仔细检查密钥和明文的环境中的结果。

    另外,请确保您不加密字符串的base64表示而不是字符串本身,或者如果您使用base64作为密钥,那么您可以一致地执行此操作。

    此外,在加密前打印两个密钥。您以编程方式构建它们,以确保您知道它们最终是什么。

    如果你确保你有相同的密钥,相同的消息,相同的编码,行结尾和表示(hex,base64等),那么使用一些在线工具进行AES加密,如:

    并比较你的哪个程序正确完成工作。

答案 1 :(得分:0)

我不是javascript或node.js专家,但我认为问题是cipher.final()Buffer正在返回Buffer.concat(...)的实例,而不是字符串。因此,您必须使用cipher = function (mode, data) { var encipher, encoded; encipher = crypto[mode]("aes-256-cbc", key, iv); cipher1 = encipher.update(data); cipher2 = encipher.final(); return Buffer.concat([cipher1, cipher2]); }; 来连接它们,即

Shader "TFTM/Skybox2CubeBlend" {
Properties {
    _Blend ("Blend", Range (0, 1) ) = 0.0
    _Rotation ("Rotation", Range(0, 360)) = 0
    _Tex ("Cubemap   (HDR)", Cube) = "grey" {}
    _OverlayTex ("CubemapOverlay (HDR)", Cube) = "grey" {}
}

SubShader {
    Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
    Cull Off ZWrite Off

    Pass {

        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #pragma target 2.0

        #include "UnityCG.cginc"

        samplerCUBE _Tex;
        samplerCUBE _OverlayTex;
        half4 _Tex_HDR;
        half4 _Tint;
        half _Exposure;
        float _Rotation;
        float _Blend;

        float3 RotateAroundYInDegrees (float3 vertex, float degrees)
        {
            float alpha = degrees * UNITY_PI / 180.0;
            float sina, cosa;
            sincos(alpha, sina, cosa);
            float2x2 m = float2x2(cosa, -sina, sina, cosa);
            return float3(mul(m, vertex.xz), vertex.y).xzy;
        }

        struct appdata_t {
            float4 vertex : POSITION;
        };

        struct v2f {
            float4 vertex : SV_POSITION;
            float3 texcoord : TEXCOORD0;
        };

        v2f vert (appdata_t v)
        {
            v2f o;
            float3 rotated = RotateAroundYInDegrees(v.vertex, _Rotation);
            o.vertex = UnityObjectToClipPos(rotated);
            o.texcoord = v.vertex.xyz;
            return o;
        }

        fixed4 frag (v2f i) : SV_Target
        {
            half4 tex = texCUBE (_Tex, i.texcoord);
            half4 tex2 = texCUBE (_OverlayTex, i.texcoord);
            float4 env = lerp( tex, tex2, _Blend );

            half3 c = DecodeHDR (env, _Tex_HDR);

            return half4(c, 1);
        }
        ENDCG 
    }
}   
Fallback Off

}

此外,在任何努力实现可移植性或互操作性的代码中,绝不应该使用此regular expression方法或此String.getBytes()构造函数。相反,请始终明确指定charset。我会推荐UTF_8,例如所以请使用String(byte[])String.getBytes(StandardCharsets.UTF_8)