【问题标题】:Encrypting and decrypting a string加密和解密字符串
【发布时间】:2014-10-17 19:39:45
【问题描述】:

我尝试按照 SO 上的一个示例来加密和解密字符串。

这是我目前所拥有的:

public static String encrypt(String value) {
        byte[] encrypted = null;
        String encrypted_string = null;
        try {

            byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
            Key skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] iv = new byte[cipher.getBlockSize()];

            IvParameterSpec ivParams = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams);
            encrypted  = cipher.doFinal(value.getBytes());
            System.out.println("encrypted string:" + encrypted.length);

            //Encrypted byte array
            System.out.println("encrypted byte array:" + encrypted);

            //Encrypted string
            encrypted_string = new String(encrypted);
            System.out.println("encrypted string: " + encrypted_string);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return encrypted_string;
    }

    public static String decrypt(String encrypted_string) {
        byte[] original = null;
        Cipher cipher = null;
        String decrypted_string = null;
        try {
            byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
            Key key = new SecretKeySpec(raw, "AES");
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            //the block size (in bytes), or 0 if the underlying algorithm is not a block cipher
            byte[] ivByte = new byte[cipher.getBlockSize()];
            //This class specifies an initialization vector (IV). Examples which use
            //IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation.
            IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
            cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec);
            original= cipher.doFinal(encrypted_string.getBytes());

            //Converts byte array to String
            decrypted_string = new String(original);
            System.out.println("Text Decrypted : " + decrypted_string);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return decrypted_string;
    }

我希望能够加密一个字符串,然后返回一个加密的字符串。然后获取该加密字符串并将其传递给我的解密方法,该方法也返回原始解密字符串。

我遵循了一个使用 Byte[] 数组的示例,但我不想使用 Byte 数组,我只想使用字符串。

上面的问题是我在这一行得到一个错误:

original= cipher.doFinal(encrypted_string.getBytes());

上面写着“错误的最终块长度:IllegalBlockSizeException”。这让我觉得我不能简单地将我的字符串转换为字节数组并将其传递给 doFinal() 方法。但是我该怎么做才能以上面想要的格式解决这个问题?

【问题讨论】:

  • 几乎所有加密算法都适用于字节,而不是字符串。接受你需要来回转换。也就是说,您可以使用string.getBytes(StandardCharsets.UTF_8)new String(bytes, StandardCharsets.UTF_8) 在字符串及其字节数组表示之间进行有效转换。
  • 如果您更愿意将密文作为字符串而不是字节来处理,您可能还想考虑使用 Base-64。

标签: java android string encryption cryptography


【解决方案1】:

当您将随机字节数组(典型的签名)转换为字符串时, 所有不可打印的字符都将替换为替换字符。 替代字符取决于使用的编码。对于 ASCII 这是 ? (3F 十六进制) 对于 UTF-8,这是 �(EFBFBD 十六进制)。

public String(byte[] bytes) 使用默认编码进行转换,对于您的应用程序可能是 UTF-8。然后String.getBytes() 将字符串数据转换回默认编码,你会得到很多 EFBFBD 用于原始数据的每个不可打印字符,使其更长。 AES 又是块密码,它在 16 字节块上运行。因此,所有密码 文本的长度与 16 成正比。这就是你得到无效块大小的原因, 何时将损坏的数据提供给 AES 解密。

将二进制数据转换为字符串表示的一种可能性是 Base64 编码。 在 Android 上可以使用 Base64 类来完成:

String encryptedString = Base64.encodeToString(encrypted, Base64.DEFAULT);
byte[] encrypted2 = Base64.decode(encryptedString, Base64.DEFAULT);

【讨论】:

  • Java 8 也有 Base64 编码(包括 URL 安全编码)。使用十六进制编码也是相当标准的。
  • 是的,但是 Android 什么时候会获得 Java 8 支持?
  • 没有注意到那个标签。无论如何可能会感兴趣。
最近更新 更多