/*
 * Copyright [2020] [MaxKey of copyright http://www.maxkey.top]
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 

/**
 * 
 */
package org.maxkey.crypto.signature;

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import org.maxkey.crypto.Base64Utils;
import org.maxkey.crypto.KeyPairType;

/**
 * RSA Digital signature
 * default signature  algorithm is SHA1withRSA
 * default key size is 1024
 * RsaSigner support MD5withRSA and MD5withRSA
 * @author Crystal.Sea
 *
 */

public final class RsaSigner implements ISigner {

	public static final KeyPairType KEY_ALGORTHM = KeyPairType.RSA;

	public  final class RsaAlgorithm {
		public static final String MD5withRSA="MD5withRSA";
		public static final String SHA1withRSA = "SHA1withRSA";
	}

	public static final String SIGNATURE_ALGORITHM = RsaAlgorithm.SHA1withRSA;

	public byte[] sign(byte[] dataBytes, byte[] privateKeyBytes, String algorithm)throws Exception {
		// ����PKCS8EncodedKeySpec����
		PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
		// ָ�������㷨
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM.name());
		// ȡ˽Կ�׶���
		PrivateKey signPrivateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
		// ��˽Կ����Ϣ�������ǩ��
		Signature signature = Signature.getInstance(algorithm);
		signature.initSign(signPrivateKey);
		signature.update(dataBytes);

		return signature.sign();
	}
	
	public byte[] sign(byte[] dataBytes, byte[] privateKeyBytes) throws Exception {
		return sign(dataBytes,privateKeyBytes,SIGNATURE_ALGORITHM);
	}

	/**
	 * sign with BASE64 privateKey use SHA1withRSA Algorithm
	 */
	public String signB64(String data, String privateKey) throws Exception {
		byte[] keyBytes = Base64Utils.decoder(privateKey);
		byte[] dataBytes = data.getBytes();
		byte[] signature=sign(dataBytes,keyBytes);

		return Base64Utils.encoder(signature);
	}



	public boolean verify(byte[] dataBytes, byte[] publicKeyBytes , byte[] signBytes,String algorithm)throws Exception {
		// ����X509EncodedKeySpec����
		X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);
		// ָ�������㷨
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM.name());
		// ȡ��Կ�׶���
		PublicKey verifyPublicKey = keyFactory.generatePublic(x509EncodedKeySpec);

		Signature signature = Signature.getInstance(algorithm);
		signature.initVerify(verifyPublicKey);

		signature.update(dataBytes);
		// verify
		return signature.verify(signBytes);
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.connsec.crypto.signature.Signer#verify(java.lang.String,
	 * java.lang.String, java.lang.String)
	 */
	public boolean verify(byte[] dataBytes, byte[] publicKeyBytes , byte[] signBytes)throws Exception {
		// verify
		return verify(dataBytes,publicKeyBytes,signBytes,SIGNATURE_ALGORITHM);
	}
	/*
	 * (non-Javadoc)
	 * @param publicKey is base64
	 * @param sign is base64
	 * @see com.connsec.crypto.signature.Signer#verify(java.lang.String,
	 * java.lang.String, java.lang.String)
	 */
	public boolean verifyB64(String data, String publicKey, String sign)throws Exception {
		// ���ܹ�Կ
		byte[] keyBytes = Base64Utils.decoder(publicKey);
		byte[] dataBytes = data.getBytes();
		byte[] signBytes=Base64Utils.decoder(sign);
		// ��֤ǩ���Ƿ���
		return verify(dataBytes,keyBytes,signBytes);
	}



}
