【问题标题】:Java BouncyCastle Cast6Engine (CAST-256) encryptingJava BouncyCastle Cast6Engine (CAST-256) 加密
【发布时间】:2013-08-01 01:48:50
【问题描述】:

我正在尝试实现一个函数,它接收一个字符串并返回 CAST-256 中字符串的编码值。以下代码是我按照 BoncyCastle 官方网页(http://www.bouncycastle.org/specifications.html,第 4.1 点)上的示例实现的。

import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.engines.CAST6Engine;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;


public class Test {

    static{
        Security.addProvider(new BouncyCastleProvider());
    }

    public static final String UTF8 = "utf-8";
    public static final String KEY = "CLp4j13gADa9AmRsqsXGJ";

    public static byte[] encrypt(String inputString) throws UnsupportedEncodingException {
        final BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CAST6Engine());
        byte[] key = KEY.getBytes(UTF8);
        byte[] input = inputString.getBytes(UTF8);
        cipher.init(true, new KeyParameter(key));

        byte[] cipherText = new byte[cipher.getOutputSize(input.length)];

        int outputLen = cipher.processBytes(input, 0, input.length, cipherText, 0);
        try {
            cipher.doFinal(cipherText, outputLen);
        } catch (CryptoException ce) {
            System.err.println(ce);
           System.exit(1);
        }
        return cipherText;
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        final String toEncrypt = "hola";
        final String encrypted = new String(Base64.encode(test(toEncrypt)),UTF8);
        System.out.println(encrypted);
    }

}

但是,当我运行我的代码时,我得到了

QUrYzMVlbx3OK6IKXWq1ng==

如果你用相同的密钥在 CAST-256 中编​​码hola(如果你想要http://www.tools4noobs.com/online_tools/encrypt/,请在此处尝试)我应该得到

w5nZSYEyA8HuPL5V0J29Yg==.

发生了什么?为什么我得到一个错误的加密字符串?

我厌倦了在互联网上找到答案,但没有找到答案。

【问题讨论】:

    标签: java encryption bouncycastle


    【解决方案1】:

    Bouncy Castle 默认使用 PKCS #7 填充,而 PHP 的 mcrypt(以及您链接的网站)默认使用零填充。这会导致不同的密文。

    请注意,此处使用的 ECB 模式几乎不适合任何用途。另外,我希望您发布的密钥不是真正的密钥,因为现在它不再是秘密了,所有这些加密都没用。

    【讨论】:

    • jeje 是的!关键是失败!但是我怎样才能像 PHP 一样使用 mcrypt?我需要对 PHP 进行相同的加密,因为我在 Java 中实现了一个 cakePHP 服务器。
    【解决方案2】:

    这并不能真正回答您的问题,但确实提供了一些指导。

    您需要进行一些挖掘以确保您以与 PHP 的 mcrypt() 完全相同的方式进行解密。您需要确保您的密钥生成、编码/解码和密码算法完全匹配。

    按键

    "CLp4j13gADa9AmRsqsXGJ".getBytes("UTF-8");
    

    可能不是创建关键源字节的正确方法。 docs 似乎表明 mcrypt() 如果大小不合适,则用 \0 填充键和数据。请注意,您的方法会生成一个 168 位密钥,这不是有效的密钥大小,我不确定 java 会对此做什么。

    算法
    确保密码模式和填充相同。 mcrypt() 是否使用 ECB、CBC 或其他东西?

    编码
    密码适用于字节,而不是字符串。确保两者之间的转换在 java 和 PHP 中是相同的。

    这是使用来自https://www.rfc-editor.org/rfc/rfc2612#page-10 的测试向量的 CAST6 参考测试。注意密钥、密文和明文都是十六进制编码的。

    import java.security.Provider;
    
    import javax.crypto.Cipher;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.apache.commons.codec.binary.Hex;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    public class Cast6 {
    
        static final String KEY_ALGO = "CAST6";
        static final String CIPHER_ALGO = "CAST6/ECB/NOPADDING";
        
        static String keytext = "2342bb9efa38542c0af75647f29f615d";
        static String plaintext = "00000000000000000000000000000000";
        static String ciphertext = "c842a08972b43d20836c91d1b7530f6b";
        
        static Provider bc = new BouncyCastleProvider();
        
        public static void main(String[] args) throws Exception {
            
            System.out.println("encrypting");
            String actual = encrypt();
            System.out.println("actual: " + actual);
            System.out.println("expect: " + ciphertext);
    
            System.out.println("decrypting");
            actual = decrypt();
            System.out.println("actual: " + actual);
            System.out.println("expect: " + plaintext);
        }
    
        static String encrypt() throws Exception {
            Cipher cipher = Cipher.getInstance(CIPHER_ALGO, bc);
            
            byte[] keyBytes = Hex.decodeHex(keytext.toCharArray());
            SecretKeySpec key = new SecretKeySpec(keyBytes, KEY_ALGO);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            
            byte[] input = Hex.decodeHex(plaintext.toCharArray());
            byte[] output = cipher.doFinal(input);
            String actual = Hex.encodeHexString(output);
            return actual;
        }
        
    
        static String decrypt() throws Exception {
            Cipher cipher = Cipher.getInstance(CIPHER_ALGO, bc);
            
            byte[] keyBytes = Hex.decodeHex(keytext.toCharArray());
            SecretKeySpec key = new SecretKeySpec(keyBytes, KEY_ALGO);
            cipher.init(Cipher.DECRYPT_MODE, key);
            
            byte[] output = cipher.doFinal(Hex.decodeHex(ciphertext.toCharArray()));
            
            String actual = Hex.encodeHexString(output);
            return actual;  
        }
    
    }
    

    【讨论】:

    • 如果您尝试使用该密钥和tools4noobs.com/online_tools/encrypt 中的明文进行加密,您将不会得到相同的结果。我需要得到与该页面相同的结果。
    • @JoseF - 是的,我知道。这就是为什么您需要深入研究 PHP 并弄清楚它到底在做什么。上述密钥/明文/密文正确的,它们是旨在帮助测试密码实现的测试向量之一。请注意,要使用十六进制键,您可能希望在 PHP 中使用 $key = pack('H*', "2342bb9efa38542c0af75647f29f615d");
    猜你喜欢
    • 1970-01-01
    • 2015-09-21
    • 2015-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-24
    相关资源
    最近更新 更多