All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mizhousoft.weixin.cipher.impl.CipherServiceImpl Maven / Gradle / Ivy

There is a newer version: 2.0.4
Show newest version
package com.mizhousoft.weixin.cipher.impl;

import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.X509Certificate;
import java.util.Base64;

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

import com.mizhousoft.weixin.certificate.CertificateProvider;
import com.mizhousoft.weixin.cipher.CipherService;
import com.mizhousoft.weixin.common.WXException;

/**
 * 密文服务
 *
 */
public class CipherServiceImpl implements CipherService
{
	public static String ALGORITHM = "SHA256-RSA2048";

	public static String SHA256WITHRSA = "SHA256withRSA";

	/**
	 * 商户密钥
	 */
	private volatile String apiV3Key;

	/**
	 * 商户私钥
	 */
	private volatile PrivateKey mchPrivKey;

	/**
	 * 微信支付平台公钥
	 */
	private volatile PublicKey platformPubKey;

	/**
	 * 证书提供者
	 */
	private CertificateProvider certificateProvider;

	/**
	 * 构造函数
	 *
	 * @param apiV3Key
	 * @param mchPrivKey
	 * @param platformPubKey
	 * @param certificateProvider
	 */
	public CipherServiceImpl(String apiV3Key, PrivateKey mchPrivKey, PublicKey platformPubKey, CertificateProvider certificateProvider)
	{
		super();
		this.apiV3Key = apiV3Key;
		this.mchPrivKey = mchPrivKey;
		this.platformPubKey = platformPubKey;
		this.certificateProvider = certificateProvider;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String decryptResult(String associatedData, String nonce, String ciphertext) throws WXException
	{
		try
		{
			Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

			SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(), "AES");
			GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes());

			cipher.init(Cipher.DECRYPT_MODE, key, spec);
			cipher.updateAAD(associatedData.getBytes());

			return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
		}
		catch (NoSuchAlgorithmException | NoSuchPaddingException e)
		{
			throw new WXException(e.getMessage(), e);
		}
		catch (InvalidKeyException | InvalidAlgorithmParameterException e)
		{
			throw new WXException(e.getMessage(), e);
		}
		catch (IllegalBlockSizeException e)
		{
			throw new WXException(e.getMessage(), e);
		}
		catch (BadPaddingException e)
		{
			throw new WXException(e.getMessage(), e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String decryptSensitiveField(String ciphertext) throws WXException
	{
		try
		{
			Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");

			cipher.init(Cipher.DECRYPT_MODE, mchPrivKey);

			return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
		}
		catch (NoSuchAlgorithmException | NoSuchPaddingException e)
		{
			throw new IllegalArgumentException("The current Java environment does not support RSA.", e);
		}
		catch (InvalidKeyException e)
		{
			throw new WXException("The given private key is invalid for decryption", e);
		}
		catch (BadPaddingException | IllegalBlockSizeException e)
		{
			throw new WXException("Decryption failed", e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String encryptSensitiveField(String plaintext) throws WXException
	{
		try
		{
			Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");

			cipher.init(Cipher.ENCRYPT_MODE, platformPubKey);

			return Base64.getEncoder().encodeToString(cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)));
		}
		catch (NoSuchAlgorithmException | NoSuchPaddingException e)
		{
			throw new IllegalArgumentException("The current Java environment does not support RSA.", e);
		}
		catch (InvalidKeyException e)
		{
			throw new WXException("RSA encryption using an illegal publicKey", e);
		}
		catch (BadPaddingException | IllegalBlockSizeException e)
		{
			throw new WXException("Plaintext is too long.", e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String sign(String message) throws WXException
	{
		try
		{
			Signature signature = Signature.getInstance(SHA256WITHRSA);

			signature.initSign(mchPrivKey);
			signature.update(message.getBytes(StandardCharsets.UTF_8));
			byte[] sign = signature.sign();

			return Base64.getEncoder().encodeToString(sign);
		}
		catch (NoSuchAlgorithmException e)
		{
			throw new IllegalArgumentException("The current Java environment does not support RSA.", e);
		}
		catch (InvalidKeyException e)
		{
			throw new WXException(SHA256WITHRSA + " signature uses an illegal privateKey.", e);
		}
		catch (SignatureException e)
		{
			throw new WXException("An error occurred during the sign process.", e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean verify(String serialNumber, String message, String signature) throws WXException
	{
		X509Certificate certificate = certificateProvider.getCertificate(serialNumber);

		try
		{
			Signature sign = Signature.getInstance(SHA256WITHRSA);
			sign.initVerify(certificate);
			sign.update(message.getBytes(StandardCharsets.UTF_8));
			return sign.verify(Base64.getDecoder().decode(signature));
		}
		catch (SignatureException e)
		{
			throw new WXException("Sign failed.", e);
		}
		catch (InvalidKeyException e)
		{
			throw new WXException("Verify uses an illegal certificate.", e);
		}
		catch (NoSuchAlgorithmException e)
		{
			throw new WXException("The current Java environment does not support " + SHA256WITHRSA, e);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy