Basic encryption and decryption problems: Conversion of byte arrays and (hexadecimal) strings, encryption and decryption in hexadecimal format

Source: Internet
Author: User

Basic encryption and decryption problems: Conversion of byte arrays and (hexadecimal) strings, encryption and decryption in hexadecimal format

During encryption, encryption algorithms and hash algorithms operate on Byte arrays. These algorithms perform various transformations and operations on Byte arrays based on encryption algorithms. The results obtained are also byte arrays. In general, encryption is required for strings. Therefore, the conversion from String to byte [] is involved. This is very simple. At the same time, the conversion from byte [] to String is also involved in decryption. In addition, after hash encryption is performed on the user's password, it is stored in the database. Therefore, the encrypted byte [] must also be converted to String.

1.String to byte [] conversion is very simple, because the String class has direct functions:

    public byte[] getBytes(Charset charset) {        if (charset == null) throw new NullPointerException();        return StringCoding.encode(charset, value, 0, value.length);    }    /**     * Encodes this {@code String} into a sequence of bytes using the     * platform's default charset, storing the result into a new byte array.     *     * @return  The resultant byte array     *     * @since      JDK1.1     */    public byte[] getBytes() {        return StringCoding.encode(value, 0, value.length);    }

2.However, the conversion from byte [] to String is not that simple.

The reason is that we cannot simply use the String function:

     /**     * Constructs a new {@code String} by decoding the specified array of bytes     * using the platform's default charset.  The length of the new {@code     * String} is a function of the charset, and hence may not be equal to the     * length of the byte array.     *     * <p> The behavior of this constructor when the given bytes are not valid     * in the default charset is unspecified.  The {@link     * java.nio.charset.CharsetDecoder} class should be used when more control     * over the decoding process is required.*/    public String(byte bytes[]) {        this(bytes, 0, bytes.length);    }   /**     * Constructs a new {@code String} by decoding the specified array of     * bytes using the specified {@linkplain java.nio.charset.Charset charset}.     * The length of the new {@code String} is a function of the charset, and     * hence may not be equal to the length of the byte array.     *     * <p> This method always replaces malformed-input and unmappable-character     * sequences with this charset's default replacement string.  The {@link     * java.nio.charset.CharsetDecoder} class should be used when more control     * over the decoding process is required.*/    public String(byte bytes[], Charset charset) {        this(bytes, 0, bytes.length, charset);    }

That is, you cannot use new String (byte) or new String (byte, charset ).

Why?

Very simple because, MD5, SHA-256, SHA-512 and other algorithms, they are through the byte [] for various transformations and operations, get encrypted byte [], the encrypted byte [] results will obviously not comply with any encoding scheme, such as UTF-8 and GBK,Because the encryption process is arbitrary for byte [] operations. Therefore, if you use any encoding scheme to decode the encrypted byte [] results, the results will be garbled..

So how can we convert the encrypted result byte [] to a String?

First, let's ask, why do we need to convert the encrypted byte [] to a String?

The answer is: first, you need to store the encrypted results, for example, in the database, and second, when one-way irreversible hash encryption algorithm encrypts the password, we need to determine whether the user's logon password is correct, so we need to compare two encrypted byte [] to see if they are consistent. Compare two byte []. You can compare one single byte at a time or multiple byte at a time. You can also convert it to a String and then compare two strings. Because the encrypted results need to be stored, they are converted to strings for comparison.

During encryption and decryption, the byte [] To String Conversion method is to use the byte [] binary representation using the hexadecimal char [], each byte is 8 bits, each 4 bits corresponds to a hexadecimal character. Therefore, a byte corresponds to two hexadecimal characters:

public class HexUtil {    private static final char[] DIGITS = {            '0', '1', '2', '3', '4', '5', '6', '7',            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'    };    public static String encodeToString(byte[] bytes) {        char[] encodedChars = encode(bytes);        return new String(encodedChars);    }    public static char[] encode(byte[] data) {        int l = data.length;        char[] out = new char[l << 1];        // two characters form the hex value.        for (int i = 0, j = 0; i < l; i++) {            out[j++] = DIGITS[(0xF0 & data[i]) >>> 4];            out[j++] = DIGITS[0x0F & data[i]];        }        return out;    }

We know that the hexadecimal expression uses the 16 numbers and letters 0-9 abcdef to represent the 16 numbers 0-15. Obviously, during String Conversion, the character '0' can be used to represent the number 0, '1' can be used to represent 1, and 'F' can be used to represent 15.

So we can see that in hexadecimal notation, the "0-9abcdef" 16 characters are used to represent the 16 numbers 0-15. The main conversion process is the public static char [] encode (byte [] data) function:

Int l = data. length; char [] out = new char [l <1]; these two statements initialize a char [] array, the array size is twice the size of the byte [] parameter, because each byte [] is converted to a 2-bit hexadecimal char [].

(0xF0 & data [I]) >>> 4 indicates that 0xF0 & data [I] is used first to remove the values in the lower 4 bits (in fact, this step is redundant ), move the 4-digit value to the right to obtain the 4-digit high of the I-th byte in the byte [] array. Then, use the DIGITS [] array to obtain the 4-digit high as the corresponding character;

DIGITS [0x0F & data [I] indicates that 0x0F & data [I] is used first, and the value on the 4-digit height is removed, and the value of the 4-digit height is obtained, then, use the DIGITS [] array to get the 4 lower as the corresponding character;

In this way, the byte [] array can be converted into a hexadecimal char []. New String (encodedChars); returns the String type.

Therefore, the final String is composed of: '0', '1', '2', '3', '4', '5', '6', '7 ', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' a String consisting of 16 characters, it does not contain any letters. For example, g, h, jklmn.

3.Reverse conversion: String to byte []

The preceding Code converts byte [] to String. The encoding scheme uses hexadecimal encoding. So how to perform reverse decoding? That is to say, convert the hexadecimal String into the original byte?

    /**     * Converts the specified Hex-encoded String into a raw byte array.  This is a     * convenience method that merely delegates to {@link #decode(char[])} using the     * argument's hex.toCharArray() value.     *     * @param hex a Hex-encoded String.     * @return A byte array containing binary data decoded from the supplied String's char array.     */    public static byte[] decode(String hex) {        return decode(hex.toCharArray());    }    /**     * Converts an array of characters representing hexidecimal values into an     * array of bytes of those same values. The returned array will be half the     * length of the passed array, as it takes two characters to represent any     * given byte. An exception is thrown if the passed char array has an odd     * number of elements.     *     * @param data An array of characters containing hexidecimal digits     * @return A byte array containing binary data decoded from     *         the supplied char array.     * @throws IllegalArgumentException if an odd number or illegal of characters     *                                  is supplied     */    public static byte[] decode(char[] data) throws IllegalArgumentException {        int len = data.length;        if ((len & 0x01) != 0) {            throw new IllegalArgumentException("Odd number of characters.");        }        byte[] out = new byte[len >> 1];        // two characters form the hex value.        for (int i = 0, j = 0; j < len; i++) {            int f = toDigit(data[j], j) << 4;            j++;            f = f | toDigit(data[j], j);            j++;            out[i] = (byte) (f & 0xFF);        }        return out;    }
    protected static int toDigit(char ch, int index) throws IllegalArgumentException {
        int digit = Character.digit(ch, 16);
        if (digit == -1) {
            throw new IllegalArgumentException("Illegal hexadecimal charcter " + ch + " at index " + index);
        }
        return digit;
    }

To convert a hex encoded String to the original byte [], the first step is to convert the String type to the char [] array, that is, to convert "10ae4f" to ['1', '0', 'A', 'E', '4', 'F'], then convert two connected char into a byte. obviously, the size of the char [] array must be an even number.

Byte [] out = new byte [len> 1]; byte [] returns half the size of char.

ToDigit (data [j], j) <4 indicates that toDigit () converts a character to a hexadecimal int, that is, '0' to a number 0, convert 'F' to the number f, and then shift the value 4 to the 4-digit height of byte;

F = f | toDigit (data [j], j); indicates that a number corresponding to the character is obtained first, and then used as a combination of the lower 4 bits and the higher 4 bits (using the | Operator) is a complete 8-bit byte.

Out [I] = (byte) (f & 0xFF); retain only 8 bits, remove the extra high.

It is actually the reverse process above.

4.Example

Public class EncodeTest {public static void main (String [] args) {String str = "??? Hello/sasewredfdd >>>. Hello world! "; System. out. println ("str. getBytes () = "+ str. getBytes (); System. out. println ("Base64 =" + Base64.encodeToString (str. getBytes (); String hexStr = HexUtil. encodeToString (str. getBytes (); // str. getBytes (Charset. forName ("UTF-8"); System. out. println ("hexStr =" + hexStr); String orignalStr = new String (str. getBytes (); // new String (str. getBytes (), Charset. forName ("UTF-8"); System. out. println ("orignalStr =" + orignalStr); String str2 = new String (HexUtil. decode (hexStr); System. out. println ("str2 =" + str2); System. out. println (str. equals (str2); String sha = new SimpleHash ("SHA-256", str, "11d23ccf28fc1e8cbab8fea97f101fc1d", 2 ). toString (); System. out. println ("sha =" + sha );}}

Result:

Str. getBytes () = [B @ 19e0bfdBase64 = Pz8/aGVsbG8vc2FzZXdyZWRmZGQ + Pj4uIEhlbGxvIOS4lueVjO + 8gQ = hexStr = ??? Hello/sasewredfdd >>>. Hello world! Str2 = ??? Hello/sasewredfdd >>>. Hello world! Truesha = 37a9715fecb5e2f9812d4a02570636e3d5fe476fc67ac34bc1_d6a8f835635d

Last new SimpleHash ("SHA-256", str, "11d23ccf28fc1e8cbab8fea97f101fc1d", 2 ). toString (), its. the toString () method is to convert the hash-encrypted byte [] into a hexadecimal string using the hexadecimal encoding.

The result is as follows: 37a9715fecb5e2f9812d4a02570636e3d5fe476fc67ac34bc1_d6a8f835635d.

All by '0', '1', '2', '3', '4', '5', '6', '7', '8 ', '9', 'A', 'B', 'C', 'D', 'E', or 'F. It does not contain any other characters.

We also have the Base64 encoding scheme above:

Base64.encodeToString (str. getBytes ())

It is actually using a-z, A-Z, 0-9,/, + these 64 characters for encoding, 0-63 respectively on the application of the previous 64 characters to represent.

The encoding result may end with one or two =:

Pz8/aGVsbG8vc2FzZXdyZWRmZGQ + Pj4uIEhlbGxvIOS4lueVjO + 8gQ=

The reason is that the Base64 encoding algorithm processes three consecutive bytes in the byte [] array each time, it is possible that the byte [] array is not an integer multiple of 3, then the remainder may be 1 or 2, so one = and two = are used for filling.

Therefore:

Base64 encoding is characterized by one or two = characters at the end, which may contain/and + characters.

Hexadecimal encoding is characterized by '0', '1', '2', '3', '4', '5', '6 ', '7', '8', '9', 'A', 'B', 'C', 'D', 'E ', 'F' consists of 16 characters, excluding other letters.

The encryption algorithms perform transformations and operations on byte.

If byte [] is obtained from String Conversion, you can use the original encoding scheme to convert it to the original String,

However, the encrypted result byte [] cannot be obtained using any character encoding scheme. Generally, the String is encoded in hexadecimal notation and then stored or compared.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.