首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java解密和加密与SJCL兼容吗?

Java解密和加密与SJCL兼容吗?
EN

Stack Overflow用户
提问于 2012-02-25 15:54:33
回答 3查看 4.9K关注 0票数 5

我需要用Java (在安卓上)和SJCL来加密和解密数据(我可以合理地切换到另一个JS加密库,但我熟悉SJCL,所以如果可能的话,我更愿意坚持使用它)。

我让SJCL端工作得很好,但是在Java端,我不确定需要使用什么参数来设置密钥生成器和密码。到目前为止,我解密的代码是:

代码语言:javascript
复制
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(ciphertext), "UTF-8");
return plaintext;

其中,salt、iv和密文作为字符串从SJCL产生的JSON对象中提取出来,然后使用Base64解码器解码为字节数组。

不幸的是,我在这方面有一些问题,上面的代码不能工作。

我遇到的第一个问题是,PBKDF2WithHmacSHA256似乎不是一个公认的密钥生成算法。我不能完全确定这就是我想要的,但根据阅读SJCL文档,它似乎是正确的?Java可以识别PBKDF2WithHmacSHA1,但这似乎不是SJCL实现的算法。

其次,如果我尝试使用SHA1密钥算法,我得到一个关于无效密钥大小的错误。我需要安装一些东西来启用256位密钥的AES吗?告诉密钥工厂生成128位密钥可以正常工作(尽管显然与使用256位密钥的SJCL不兼容)。

第三,我应该使用哪种加密模式?我很确定CBC是不对的..。SJCL的文档同时提到了CCM和OCB,但是Java似乎不支持开箱即用的任何一种--同样,我需要安装一些东西才能使其工作吗?SJCL默认使用哪一个?

最后,即使我选择了使Java不会抱怨缺少算法的参数,它也会抱怨通过解码SJCL输出提供的IV长度错误,这看起来肯定是错误的:结果输出中有17个字节,而不是AES显然要求的16个字节。我只是忽略最后一个字节吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-04-07 02:32:10

我还没有尝试过(最后我放弃了使用Javascript crypto,转而使用带有bouncycastle的嵌入式java applet来处理通信),但是GnuCrypto (一个bouncycastle )支持PBKDFWithHmacSHA256。SJCL中的固定字符编码处理可能修复了IV (?)的意外长度,因此这将离开密码模式。从这一点上看,最简单的方法似乎是实现一个相对简单的密码模式(例如CTR)作为SJCL的附加组件,这应该只需要几个小时的工作,即使是对代码不熟悉的人,然后它只是编码和解码SJCL使用的JSON编码的数据包(这应该是微不足道的)。

作为另一种选择,当然可以为Java实现OCB模式,尽管该算法是专有的,因为在通用公共许可证(http://www.cs.ucdavis.edu/~rogaway/ocb/grant.htm)下分发的软件有公共专利授权。

有趣的是,我想知道GnuCrypto是否会接受OCB模式支持的补丁?GnuCrypto是在GPL-with-libraries exemption下分发的,这看起来像是“自由软件基金会发布的GNU通用公共许可证的任何版本”,所以至少在理论上这应该是可能的。

票数 1
EN

Stack Overflow用户

发布于 2020-04-03 11:05:02

java中的SJCL AES

代码语言:javascript
复制
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.json.JSONObject;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.Base64.*;
import java.util.HashMap;
import java.util.Map;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 *
 * SJCL 1.0.8
 *
 * dependencies:
 * compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.64'
 * compile group: 'org.json', name: 'json', version: '20190722'
 *
 * ref: https://blog.degering.name/posts/java-sjcl
 */
public class AesSJCL {
    // Simply prints out the decoded string.
    public static void main(String[] args) throws Exception {
        String password = "password";
        String plainText = "Who am I?";

        // encryption
        Map<String, Object> result = new AesSJCL().encrypt( password, plainText);
        String json =  new JSONObject(result).toString();
        System.out.printf("encrypted output:\n%s\n", json);

        System.out.printf("\njavascript testing code:\nsjcl.decrypt(\"%s\", '%s')\n", password, json);

        // decryption
        String decryptedText = new AesSJCL().decrypt(password, json);
        System.out.printf("\ndecrypted output: \n%s\n", decryptedText);
    }

    /**
     *
     * @param password  - password
     * @param encryptedText - {"cipher":"aes","mode":"ccm","ct":"r7U/Gp2r8LVNQR7kl5qLNd8=","salt":"VwSOS3jCn6M=","v":1,"ks":128,"iter":10000,"iv":"5OEwQPtHK2ej1mHwvOf57A==","adata":"","ts":64}
     * @return
     * @throws Exception
     */
    public String decrypt(String password, String encryptedText) throws Exception {
        Decoder d = Base64.getDecoder();

        // Decode the encoded JSON and create a JSON Object from it
        JSONObject j = new JSONObject(new String(encryptedText));

        // We need the salt, the IV and the cipher text;
        // all of them need to be Base64 decoded
        byte[] salt=d.decode(j.getString("salt"));
        byte[] iv=d.decode(j.getString("iv"));
        byte[] cipherText=d.decode(j.getString("ct"));

        // Also, we need the keySize and the iteration count
        int keySize = j.getInt("ks"), iterations = j.getInt("iter");

        // https://github.com/bitwiseshiftleft/sjcl/blob/master/core/ccm.js#L60
        int lol = 2;
        if (cipherText.length >= 1<<16) lol++;
        if (cipherText.length >= 1<<24) lol++;

        // Cut the IV to the appropriate length, which is 15 - L
        iv = Arrays.copyOf(iv, 15-lol);

        // Crypto stuff.
        // First, we need the secret AES key,
        // which is generated from password and salt
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(password.toCharArray(),
                salt, iterations, keySize);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

        // Now it's time to decrypt.
        Cipher cipher = Cipher.getInstance("AES/CCM/NoPadding",
                new BouncyCastleProvider());
        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));

        // Return the final result after converting it to a string.
        return new String(cipher.doFinal(cipherText));
    }


    /**
     *
     * @param password
     * @param plainText
     * @return
     * @throws Exception
     */
    public Map<String, Object> encrypt(String password, String plainText) throws Exception {
        int iterations = 10000;  // default in SJCL
        int keySize = 128;

        // https://github.com/bitwiseshiftleft/sjcl/blob/master/core/convenience.js#L321
        // default salt bytes are 8 bytes
        SecureRandom sr = SecureRandom.getInstanceStrong();
        byte[] salt = new byte[8];
        sr.nextBytes(salt);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, keySize);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

        // https://github.com/bitwiseshiftleft/sjcl/blob/master/core/random.js#L87
        // default iv bytes are 16 bytes
        SecureRandom randomSecureRandom = SecureRandom.getInstanceStrong();
        byte[] iv = new byte[16];
        randomSecureRandom.nextBytes(iv);

        int ivl = iv.length;
        if (ivl < 7) {
            throw new RuntimeException("ccm: iv must be at least 7 bytes");
        }

        // compute the length of the length
        int ol=plainText.length();
        int L=2;
        for (; L<4 && ( ol >>> 8*L ) > 0; L++) {}
        if (L < 15 - ivl) { L = 15-ivl; }

        byte[] shortIV = Arrays.copyOf(iv, 15-L);

        // Now it's time to decrypt.
        Cipher cipher = Cipher.getInstance("AES/CCM/NoPadding", new BouncyCastleProvider());
        cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(shortIV));

        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(UTF_8));

        Encoder encoder = Base64.getEncoder();

        Map<String, Object> map = new HashMap<>();
        map.put("iv", encoder.encodeToString(iv));
        map.put("iter", iterations);
        map.put("ks", keySize);
        map.put("salt", encoder.encodeToString(salt));
        map.put("ct", encoder.encodeToString(encryptedBytes));
        map.put("cipher", "aes");
        map.put("mode", "ccm");
        map.put("adata", "");
        map.put("v", 1);   // I don't know what it is.
        map.put("ts", 64);  // I don't know what it is.

        return map;
    }
}

github gist by me

参考:Java talks SJCL

票数 0
EN

Stack Overflow用户

发布于 2012-02-26 09:58:25

您可能必须使用BouncyCastle来获取SJCL中使用的所有加密功能。确保base64正确地解码了所有内容,并且SJCL没有添加长度指示符或类似的指示符。

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

https://stackoverflow.com/questions/9442342

复制
相关文章

相似问题

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