1. 程式人生 > >Java AES512加密演算法

Java AES512加密演算法

AES - 高階加密標準:

高階加密標準(英語:Advanced Encryption Standard,縮寫:AES),在密碼學中又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣為全世界所使用。經過五年的甄選流程,高階加密標準由美國國家標準與技術研究院(NIST)於2001年11月26日釋出於FIPS PUB 197,並在2002年5月26日成為有效的標準。2006年,高階加密標準已然成為對稱金鑰加密中最流行的演算法之一

AES 演算法在工作中使用很頻繁, 藉著這次專案中使用做一下總結, 本次主要是正對 AES512 來講解。

開發前準備工作:

由於Java 執行環境中的 policy檔案是受限的,AES512不支援。解決方案如下:

1:policy檔案位於${java_home}/jre/lib/security目錄下

2: 去除該限制需下載JavaCryptography Extension (JCE) Unlimited Strength JurisdictionPolicy Files
覆蓋上述目錄下的對應jar檔案(local_policy.jar,US_export_policy.jar)

3: jar 官方下載路徑

做完這三步 下面直接上程式碼:

AES512 加密方法

package org.message.encrypt.cipher;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.message.encrypt.tool.Encode;
import org.message.encrypt.tool.Numeric;

import com.google.common.io.BaseEncoding;

public class AESCipher {
	private static final String ALGORITHM_AES256 = "AES/CBC/PKCS5Padding";// "AES/CBC/PKCS7Padding";
	private final SecretKeySpec secretKeySpec;
	private static final String CHARSET = "UTF-8";
	private static final String DEFAULT_IV = "iv is default value";
	private Cipher cipher;
	private IvParameterSpec iv;

	
	public AESCipher(String key) {
		this(key, DEFAULT_IV);
	}

	public AESCipher(String key, String iv) {
		this(Numeric.hexStringToByteArray(key), Numeric.hexStringToByteArray(iv));
	}

	private AESCipher(byte[] key, byte[] iv) {
		// Security.addProvider(new BouncyCastleProvider());
		if (null == key || key.length != 32) {
			throw new RuntimeException("input params key must be 32bit bytes array");
		}
		if (null == iv || iv.length != 16) {
			throw new RuntimeException("input params iv must be 16bit bytes array");
		}
		this.secretKeySpec = new SecretKeySpec(key, "AES");
		this.iv = new IvParameterSpec(iv);
		try {
			this.cipher = Cipher.getInstance(ALGORITHM_AES256);
		} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
			throw new RuntimeException("instantiation objects Cipher exception");
		}
	}

	/**
	 * AES Encrypt algorithm
	 * 
	 * @param encryptSource
	 *            not null string
	 * @return after AES encrypt result , the type of the string
	 */
	public String getEncryptedMessage(final String encryptSource) {
		Cipher cipher = getCipher(Cipher.ENCRYPT_MODE);
		byte[] encryptedTextBytes = null;
		try {
			encryptedTextBytes = cipher.doFinal(encryptSource.getBytes(CHARSET));
		} catch (IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException e) {
			throw new RuntimeException("AES encrypt exception");
		}
		return Encode.baseEncode(encryptedTextBytes);
	}

	/**
	 * AES decrypt algorithm
	 * 
	 * @param decryptSource
	 *            AES encrypted cipher, type of String
	 * @return decrypted plaintext, type of string
	 */
	public String getDecryptMessage(String decryptSource) {

		Cipher cipher = getCipher(Cipher.DECRYPT_MODE);
		byte[] encryptedTextBytes = null;
		String decryptResult = null;
		try {
			encryptedTextBytes = cipher.doFinal(BaseEncoding.base64().decode(decryptSource));
		} catch (IllegalBlockSizeException | BadPaddingException e) {
			throw new RuntimeException("AES decrypt exception");
		}
		try {
			decryptResult = new String(encryptedTextBytes, CHARSET);
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("bytes array convert into string exception");
		}
		return decryptResult;
	}

	private Cipher getCipher(int encryptMode) {
		try {
			cipher.init(encryptMode, secretKeySpec, iv);
		} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
			throw new RuntimeException("init objects Cipher exception");
		}
		return cipher;
	}
}


Encode 工具類
package org.message.encrypt.tool;

import com.google.common.io.BaseEncoding;

public class Encode {

	/**
	 * byte[] convert into string ,use base encode default value BASE64
	 * 
	 * @param encodeMassage
	 *            not null byte[]
	 * @return after encode result
	 */
	public static String baseEncode(final byte[] encodeMassage) {
		return baseEncode(encodeMassage, BaseType.BASE64);
	}

	/**
	 * byte[] convert into string ,use base encode default value BASE64
	 * 
	 * @param encodeMassage
	 *            not null byte[]
	 * @param encoder
	 *            of type please see enum type of inner class , the class name
	 *            'BaseType'
	 * @return after encode result , the type of string
	 */
	public static String baseEncode(final byte[] encodeMassage, final BaseType encoder) {
		String baseResult = null;
		switch (encoder) {
		case BASE64:
			baseResult = BaseEncoding.base64().encode(encodeMassage);
			break;
		case BASE32:
			baseResult = BaseEncoding.base32().encode(encodeMassage);
			break;
		case BASE32HEX:
			baseResult = BaseEncoding.base32Hex().encode(encodeMassage);
			break;
		case BASE16:
			baseResult = BaseEncoding.base16().encode(encodeMassage);
			break;
		default:
			break;
		}
		return baseResult;
	}

	/**
	 * string convert into byte[], use base decode
	 * 
	 * @param decodeMassage
	 *            not null string
	 * @return after decode result , the type of byte[]
	 */
	public static byte[] baseDecode(final String decodeMassage) {
		return baseDecode(decodeMassage, BaseType.BASE64);
	}

	public static byte[] baseDecode(final String decodeMassage, final BaseType encoder) {
		byte[] baseResult = null;
		switch (encoder) {
		case BASE64:
			baseResult = BaseEncoding.base64().decode(decodeMassage);
			break;
		case BASE32:
			baseResult = BaseEncoding.base32().decode(decodeMassage);
			break;
		case BASE32HEX:
			baseResult = BaseEncoding.base32Hex().decode(decodeMassage);
			break;
		case BASE16:
			baseResult = BaseEncoding.base16().decode(decodeMassage);
			break;
		default:
			break;
		}
		return baseResult;
	}

	enum BaseType {
		BASE64, BASE32, BASE32HEX, BASE16;
	}
}


Numeric 工具類
package org.message.encrypt.tool;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;

/**
 * <p>Message codec functions.</p>
 *
 * <p>Implementation as per https://github.com/ethereum/wiki/wiki/JSON-RPC#hex-value-encoding</p>
 */
public final class Numeric {

    private static final String HEX_PREFIX = "0x";

    private Numeric() {
    }

    public static String encodeQuantity(BigInteger value) {
        if (value.signum() != -1) {
            return HEX_PREFIX + value.toString(16);
        } else {
            throw new RuntimeException("Negative values are not supported");
        }
    }

    public static BigInteger decodeQuantity(String value) {
        if (!isValidHexQuantity(value)) {
            throw new RuntimeException("Value must be in format 0x[1-9]+[0-9]* or 0x0");
        }
        try {
            return new BigInteger(value.substring(2), 16);
        } catch (NumberFormatException e) {
            throw new RuntimeException("Negative ", e);
        }
    }

    private static boolean isValidHexQuantity(String value) {
        if (value == null) {
            return false;
        }

        if (value.length() < 3) {
            return false;
        }

        if (!value.startsWith(HEX_PREFIX)) {
            return false;
        }

        // If TestRpc resolves the following issue, we can reinstate this code
        // https://github.com/ethereumjs/testrpc/issues/220
//        if (value.length() > 3 && value.charAt(2) == '0') {
//            return false;
//        }

        return true;
    }

    public static String cleanHexPrefix(String input) {
        if (containsHexPrefix(input)) {
            return input.substring(2);
        } else {
            return input;
        }
    }

    public static String prependHexPrefix(String input) {
        if (!containsHexPrefix(input)) {
            return HEX_PREFIX + input;
        } else {
            return input;
        }
    }

    public static boolean containsHexPrefix(String input) {
        return input.length() > 1 && input.charAt(0) == '0' && input.charAt(1) == 'x';
    }

    public static BigInteger toBigInt(byte[] value, int offset, int length) {
        return toBigInt((Arrays.copyOfRange(value, offset, offset + length)));
    }

    public static BigInteger toBigInt(byte[] value) {
        return new BigInteger(1, value);
    }

    public static BigInteger toBigInt(String hexValue) {
        String cleanValue = cleanHexPrefix(hexValue);
        return new BigInteger(cleanValue, 16);
    }

    public static String toHexStringWithPrefix(BigInteger value) {
        return HEX_PREFIX + value.toString(16);
    }

    public static String toHexStringNoPrefix(BigInteger value) {
        return value.toString(16);
    }

    public static String toHexStringWithPrefixZeroPadded(BigInteger value, int size) {
        return toHexStringZeroPadded(value, size, true);
    }

    public static String toHexStringNoPrefixZeroPadded(BigInteger value, int size) {
        return toHexStringZeroPadded(value, size, false);
    }

    private static String toHexStringZeroPadded(BigInteger value, int size, boolean withPrefix) {
        String result = toHexStringNoPrefix(value);

        int length = result.length();
        if (length > size) {
            throw new UnsupportedOperationException(
                    "Value " + result + "is larger then length " + size);
        } else if (value.signum() < 0) {
            throw new UnsupportedOperationException("Value cannot be negative");
        }

        if (length < size) {
            result = Strings.zeros(size - length) + result;
        }

        if (withPrefix) {
            return HEX_PREFIX + result;
        } else {
            return result;
        }
    }

    public static byte[] toBytesPadded(BigInteger value, int length) {
        byte[] result = new byte[length];
        byte[] bytes = value.toByteArray();

        int bytesLength;
        int srcOffset;
        if (bytes[0] == 0) {
            bytesLength = bytes.length - 1;
            srcOffset = 1;
        } else {
             bytesLength = bytes.length;
            srcOffset = 0;
        }

        if (bytesLength > length) {
            throw new RuntimeException("Input is too large to put in byte array of size " + length);
        }

        int destOffset = length - bytesLength;
        System.arraycopy(bytes, srcOffset, result, destOffset, bytesLength);
        return result;
    }

    public static byte[] hexStringToByteArray(String input) {
        String cleanInput = cleanHexPrefix(input);

        int len = cleanInput.length();

        if (len == 0) {
            return new byte[] {};
        }

        byte[] data;
        int startIdx;
        if (len % 2 != 0) {
            data = new byte[(len / 2) + 1];
            data[0] = (byte) Character.digit(cleanInput.charAt(0), 16);
            startIdx = 1;
        } else {
            data = new byte[len / 2];
            startIdx = 0;
        }

        for (int i = startIdx; i < len; i += 2) {
            data[(i + 1) / 2] = (byte) ((Character.digit(cleanInput.charAt(i), 16) << 4)
                    + Character.digit(cleanInput.charAt(i+1), 16));
        }
        return data;
    }

    public static String toHexString(byte[] input, int offset, int length, boolean withPrefix) {
        StringBuilder stringBuilder = new StringBuilder();
        if (withPrefix) {
            stringBuilder.append("0x");
        }
        for (int i = offset; i < offset + length; i++) {
            stringBuilder.append(String.format("%02x", input[i] & 0xFF));
        }

        return stringBuilder.toString();
    }

    public static String toHexStringNoPrefix(byte[] input) {
        return toHexString(input, 0, input.length, false);
    }

    public static String toHexString(byte[] input) {
        return toHexString(input, 0, input.length, true);
    }

    public static byte b(int m, int n) {
        return (byte) ( (m << 4) | n);
    }

    public static boolean isIntegerValue(BigDecimal value) {
        return value.signum() == 0 ||
                value.scale() <= 0 ||
                value.stripTrailingZeros().scale() <= 0;
    }
}

好了 這樣 AES512 就實現了, 測試方法我在這就寫了, 自己可以寫個test 測試下。