java - 一个32个字符的字符串如何变成46个字节?

标签 java string utf-8 ascii

我正在尝试学习一些加密,但不知何故我被困在了一个问题上。我想对文本执行某种 AES 加密(例如,字符串“密码”)。我有 ff 代码作为我的来源:

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;


public class AES {
    static String IV = "fedcba9876543210";
    static String plaintext = "password"; /*Note null padding*/

    //static String encryptionKey = "0123456789abcdef0123456789abcdef";
    static String encKey = "cf6000c7452f9487cc03cd721a3f18482e43cdcc37c380e062193c489f968d04";
    static String encryptionKey = "";
    public static void main(String [] args) {
        try {
            System.out.print(plaintext.length() + "\n");
            if (plaintext.length() < 16) {
                int pad = 16 - plaintext.length();
                String repeated = new String(new char[pad]).replace("\0", "\0");
                plaintext = plaintext + repeated;
            }
            System.out.println("==Java==");
            System.out.println("plain:   " + plaintext);
            System.out.print(plaintext.length() + "\n");

            encryptionKey = hexToAscii(encKey);
            //encryptionKey = "0123456789abcdef0123456789abcdef";

            byte[] cipher = encrypt(plaintext, encryptionKey);
            String a = byteArrayToHex(cipher);
            System.out.print(a + "\n");

            System.out.print("cipher:  ");
            for (int i=0; i<cipher.length; i++)
                System.out.print(new Integer(cipher[i])+" ");
            System.out.println("");

            String decrypted = decrypt(cipher, encryptionKey);

            System.out.println("decrypt: " + decrypted);

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

    public static byte[] encrypt(String plainText, String string) throws Exception {
        //System.out.println("encrypting" + encryptionKey.length());


// Check length, in characters
        System.out.println("Length of string is " + string.length()); // prints "11"

// Check encoded sizes
        final byte[] utf8Bytes = string.getBytes("UTF-8");
        System.out.println(utf8Bytes.length); // prints "11"

        final byte[] utf16Bytes= string.getBytes("UTF-16");
        System.out.println(utf16Bytes.length); // prints "24"

        final byte[] utf32Bytes = string.getBytes("UTF-32");
        System.out.println(utf32Bytes.length); // prints "44"

        final byte[] isoBytes = string.getBytes("ISO-8859-1");
        System.out.println(isoBytes.length); // prints "11"

        final byte[] winBytes = string.getBytes("CP1252");
        System.out.println(winBytes.length); // prints "11"

        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        System.out.println("enc 2");

        SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
        System.out.println("enc 3");

        cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
        System.out.println("enc 4");
        return cipher.doFinal(plainText.getBytes("UTF-8"));
    }

    public static String hexToAscii(String s) {
        int n = s.length();
        StringBuilder sb = new StringBuilder(n / 2);
        for (int i = 0; i < n; i += 2) {
            char a = s.charAt(i);
            char b = s.charAt(i + 1);
            sb.append((char) ((hexToInt(a) << 4) | hexToInt(b)));
        }
        return sb.toString();
    }


    public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception{
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
        cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
        return new String(cipher.doFinal(cipherText),"UTF-8");
    }
    public static String byteArrayToHex(byte[] a) {
        StringBuilder sb = new StringBuilder(a.length * 2);
        for(byte b: a)
            sb.append(String.format("%02x", b & 0xff));
        return sb.toString();
    }

    private static int hexToInt(char ch) {
        if ('a' <= ch && ch <= 'f') { return ch - 'a' + 10; }
        if ('A' <= ch && ch <= 'F') { return ch - 'A' + 10; }
        if ('0' <= ch && ch <= '9') { return ch - '0'; }
        throw new IllegalArgumentException(String.valueOf(ch));
    }
}

字符串 "cf6000c7452f9487cc03cd721a3f18482e43cdcc37c380e062193c489f968d04" 是一个由 64 个十六进制数字组成的序列,我希望在转换为字符串时相当于 32 个字符。使用这 32 个字符作为我的 key ,我无法如上面的代码所示进行加密,因为对 key 的 getBytes 调用以某种方式将其设置为 46 字节。

在长度为 32 个字符的 0123456789abcdef0123456789abcdef 等纯字符串(非十六进制)上,整个加密过程就像使用此字符串调用 getBytes 一样,因为 key 的长度为 32 字节.

有什么想法吗?理想情况下,我想知道如何使用第一个十六进制数字序列(要转换为字符串)作为 key 来加密文本。我已经在 python 中成功地做到了这一点,但是这在 Java 中可能吗?

最佳答案

永远不要假设字符串中的一个字符占用一个字节。

这是真的,在大多数编码中,仅适用于小于 128 的字符。

由于 hexToAscii 返回一个包含 128-255 范围内字符的字符串,这些字符将被编码为一个以上的字节。

解决方案是不将键视为字符串。字符串用于文本;加密 key 不是文本,而是字节序列。而是将加密 key 存储在字节数组中。 hexToAscii 应该返回一个字节数组,encrypt 应该只需要对明文调用getBytes

关于java - 一个32个字符的字符串如何变成46个字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28034744/

相关文章:

JavaScript "firstNonRepeatingLetter"函数返回未定义而不是字符?

python - 不要用 Python 字符串 split() 拆分双引号单词?

java - 检查组模型中的 Wicket CheckGroup Ajax 口是心非

java - org.eclipse.swt.widgets.Group,这个类真的可以滚动吗

javascript - 在 Javascript 的字符串中保留 N 次出现的单个字符

MySQL UTF-8 编码

Spring Controller @ResponseBody text/xml响应UTF-8编码问题

javascript - UTF-8 编码 : Unescape(%e2%80%93) returns â instead of –

JAVA通过网络发送Scribble

java - 简单控制台测试应用程序中的 NullPointerException