【问题标题】:Blowfish example where automatically pad and unpad the key to sizeBlowfish 示例,其中自动填充和取消填充大小键
【发布时间】:2014-04-06 04:39:47
【问题描述】:

Blowfish 能够进行强加密,并且可以使用最大 56 字节的密钥(448 位密钥)。 密钥必须是 8 个字节的倍数(最多 56 个)。

我想写的例子会自动填充和取消填充键的大小。因为 Blowfish 创建了 8 字节加密输出块,所以输出也被填充和不填充到 8 字节的倍数。

其实是想写java代码来模拟—— http://webnet77.com/cgi-bin/helpers/blowfish.pl

我正在使用工具信息-

ALGORITM = "Blowfish";
HEX KEY = "92514c2df6e22f079acabedce08f8ac3";
PLAIN_TEXT = "sangasong@song.com"

工具返回-

CD3A08381467823D4013960E75E465F0B00C5E3BAEFBECBB 

请提出建议。

试过java代码:

public class TestBlowfish
{
    final String KEY = "92514c2df6e22f079acabedce08f8ac3";
    final String PLAIN_TEXT = "sangasong@song.com";
    byte[] keyBytes = DatatypeConverter.parseHexBinary(KEY); 
}

public static void main(String[] args) throws Exception 
{
    try 
    {
        byte[] encrypted = encrypt(keyBytes, PLAIN_TEXT);
        System.out.println( "Encrypted hex: " + Hex.encodeHexString(encrypted));

    }catch (GeneralSecurityException e) 
    {
        e.printStackTrace();
    }
}

private static byte[] encrypt(byte[] key, String plainText) throws GeneralSecurityException
{
    SecretKey secret_key = new SecretKeySpec(key, "Blowfish");
    Cipher cipher = Cipher.getInstance("Blowfish");
    cipher.init(Cipher.ENCRYPT_MODE, secret_key);

    return cipher.doFinal(plainText.getBytes());
} 

结果 -

Encrypted hex: 525bd4bd786a545fe7786b0076b3bbc2127425f0ea58c29d

【问题讨论】:

  • 建议...什么?到目前为止,您尝试过什么吗?为什么需要垫一个键?它应该以正确的大小生成。那你为什么要取消填充呢?
  • @Cocoop,我已经编辑了我的问题。请看看我到目前为止所做的尝试。
  • 好!现在你运行它并遇到任何错误吗?
  • 没有错误。但输出与工具不同。我们的客户端使用 webnet77 工具加密并向我们发送加密代码。在原始帖子中添加输出。
  • @Cocoop ,实际上尝试了各种方式和顺序来加密,但没有得到与工具相同的结果。

标签: java encryption cryptography blowfish


【解决方案1】:

因此,脚本使用了不正确的 PKCS#7 填充版本,当输入的大小已经可以被块大小整除时,该版本不会填充 - 无论是对于密钥还是明文。此外,它使用 ECB 模式加密。两者都不应该在现实生活场景中使用。

以下代码要求将 Bouncy Castle 提供程序添加到 JCE (Service.addProvider(new BouncyCastleProvider())),并且 Bouncy Castle 库的 Hex 类位于类路径中。

警告:仅在有限输入下进行测试,如果密钥大小大于最大值,则不会削减密钥大小。

警告:以下代码不是加密的

import org.bouncycastle.util.encoders.Hex;

public class BadBlowfish {
        private static SecretKey createKey(String theKey) {
        final byte[] keyData = theKey.getBytes(StandardCharsets.US_ASCII);
        final byte[] paddedKeyData = halfPadPKCS7(keyData, 8);
        SecretKey secret = new SecretKeySpec(paddedKeyData, "Blowfish");
        return secret;
    }

    private static byte[] halfUnpadPKCS7(final byte[] paddedPlaintext, int blocksize) {
        int b = paddedPlaintext[paddedPlaintext.length - 1] & 0xFF;
        if (b > 0x07) {
            return paddedPlaintext.clone();
        }
        return Arrays.copyOf(paddedPlaintext, paddedPlaintext.length - b);
    }

    private static byte[] halfPadPKCS7(final byte[] plaintext, int blocksize) {
        if (plaintext.length % blocksize == 0) {
            return plaintext.clone();
        }

        int newLength = (plaintext.length / blocksize + 1) * blocksize;
        int paddingLength = newLength - plaintext.length;

        final byte[] paddedPlaintext = Arrays.copyOf(plaintext, newLength);
        for (int offset = plaintext.length; offset < newLength; offset++) {
            paddedPlaintext[offset] = (byte) paddingLength;
        }
        return paddedPlaintext;
    }

    public static void main(String[] args) throws Exception {
        Cipher cipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
        SecretKey key = createKey("123456781234567");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] plaintextData = cipher.doFinal(Hex.decode("085585C60B3D23257763E6D8BB0A0891"));
        byte[] unpaddedPlaintextData = halfUnpadPKCS7(plaintextData, cipher.getBlockSize());

        String plaintextHex = Hex.toHexString(unpaddedPlaintextData);
        System.out.println(plaintextHex);
        String plaintext = new String(unpaddedPlaintextData, StandardCharsets.UTF_8);
        System.out.println(plaintext);
    }
}

【讨论】:

  • 非常感谢@owlstead。通过对您的代码进行少量编辑,我得到了我正在寻找的确切解决方案。帮助很大!
  • 你认为当我从 URL 发送加密代码时它不会起作用吗?作为独立的 java 程序工作得很好......但我得到了异常 - 获取 javax.crypto.IllegalBlockSizeException: 使用填充密码解密时输入长度必须是 8 的倍数?
  • 始终对密文进行 URL 编码。确保发送和接收时密文相同。
【解决方案2】:

我不确定这个问题的相关性:恕我直言,没有必要获得与此脚本相同的输出:您无法保证它的安全性/效率... 让我大吃一惊的是关于填充的部分:有几种填充块的解决方案,其中一些很简单但非常不安全,也许这个脚本正在使用这些“坏”解决方案之一。

您是否检查过您的程序是否能够检索正确的纯文本? (您需要对匹配的decrypt 函数进行编码)。 如果是这样,这意味着它可以正常工作,并且可以用于您最初的目的,无论此脚本的输出是什么......

【讨论】:

    猜你喜欢
    • 2023-02-15
    • 2015-04-24
    • 2014-06-07
    • 2020-05-14
    • 1970-01-01
    • 2012-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多