/**
 * Alipay.com Inc.
 * Copyright (c) 2004-2021 All Rights Reserved.
 */
package com.alipay.api.internal.util.encrypt.impl;

import com.alipay.api.AlipayApiErrorEnum;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.codec.Base64;
import com.alipay.api.internal.util.encrypt.Encrypt;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;

/**
 * @author zts
 * @version : AesEncryptV2.java, v 0.1 2021年06月23日 3:54 PM zts Exp $
 */
public class AesEncryptV2 implements Encrypt {

    private static final String SLASH = "/";
    private static final String alg = "AES";
    private static final String mode = "CBC";
    private static final String padding = "PKCS5Padding";
    private static final int ivSize = 16;

    private final String fullCipherName;

    /**
     * constructor
     */
    public AesEncryptV2() {
        this.fullCipherName = alg + SLASH + mode + SLASH + padding;
    }

    @Override
    public String encrypt(String content, String key, String charset) throws AlipayApiException {
        try {
            Cipher cipher = Cipher.getInstance(fullCipherName);

            //init iv
            byte[] iv = new byte[ivSize];
            SecureRandom random = new SecureRandom();
            random.nextBytes(iv);
            IvParameterSpec ivParams = new IvParameterSpec(iv);

            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(key.getBytes()), alg), ivParams);

            byte[] encryptedText = cipher.doFinal(content.getBytes(charset));
            byte[] ivAndEncryptedText = new byte[ivSize + encryptedText.length];

            System.arraycopy(iv, 0, ivAndEncryptedText, 0, ivSize);
            System.arraycopy(encryptedText, 0, ivAndEncryptedText, ivSize, encryptedText.length);
            return new String(Base64.encodeBase64(ivAndEncryptedText));
        } catch (Exception e) {
            throw new AlipayApiException(String.format(AlipayApiErrorEnum.ENCRYPT_ASE_V2_ERROR.getErrMsg(),
                    content, charset), e);
        }
    }

    @Override
    public String decrypt(String content, String key, String charset) throws AlipayApiException {
        try {
            byte[] ivAndEncryptedText = Base64.decodeBase64(content.getBytes());

            Cipher cipher = Cipher.getInstance(fullCipherName);

            IvParameterSpec ivParameterSpec = new IvParameterSpec(ivAndEncryptedText, 0, ivSize);

            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(key.getBytes()), alg), ivParameterSpec);

            byte[] contentBytes = cipher.doFinal(ivAndEncryptedText, ivSize, ivAndEncryptedText.length - ivSize);
            return new String(contentBytes, charset);
        } catch (Exception e) {
            throw new AlipayApiException(String.format(AlipayApiErrorEnum.DECRYPT_ASE_V2_ERROR.getErrMsg(),
                    content, charset), e);
        }

    }
}