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

com.github.flysium.io.yew.common.crypto.impl.RSA Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2018-2025 the original author or authors.
 *
 * 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 com.github.flysium.io.yew.common.crypto.impl;

import com.github.flysium.io.yew.common.crypto.AbstractAsymmetric;
import com.github.flysium.io.yew.common.crypto.AsyCryptoSpi;
import com.github.flysium.io.yew.common.crypto.SecretSpi;
import com.github.flysium.io.yew.common.crypto.support.CryptoUtil;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.Provider;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import org.apache.commons.lang3.StringUtils;

/**
 * RSA
 *
 * @author Sven Augustus
 * @version 1.0
 * @since JDK 1.7
 */
public class RSA extends AbstractAsymmetric implements AsyCryptoSpi, SecretSpi {

	/**
	 * The RSA encryption algorithm as defined in PKCS #1
	 */
	private static final String DEFAULT_ALGORITHM = "RSA";
	/**
	 * default transforms
	 */
	private static final String DEFAULT_TRANSFORMS = "RSA";
	/**
	 * default key length,1024 bits
	 */
	public static final int DEFAULT_KEY_SIZE = 1024;
	/**
	 * default signature algorithm
	 */
	private static final String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withRSA";


	public RSA() {
		this(NULL_PROVIDER, DEFAULT_TRANSFORMS);
	}

	public RSA(Provider provider) {
		this(provider, DEFAULT_TRANSFORMS);
	}

	public RSA(String transforms) {
		this(NULL_PROVIDER, transforms);
	}

	public RSA(Provider provider, String transforms) {
		super(DEFAULT_ALGORITHM, provider, transforms);
		super.setSignatureAlgorithm(DEFAULT_SIGNATURE_ALGORITHM);
	}

	public RSA(String publicKeyStr, String privateKeyStr) {
		this(null, DEFAULT_TRANSFORMS, publicKeyStr, privateKeyStr);
	}

	public RSA(Provider provider, String transforms, String publicKeyB64, String privateKeyB64) {
		super(DEFAULT_ALGORITHM, provider, transforms, publicKeyB64, privateKeyB64);
		super.setSignatureAlgorithm(DEFAULT_SIGNATURE_ALGORITHM);
	}

	/**
	 * Set public key
	 *
	 * @param publicKeyB64 Base64 encoded public key text
	 */
	@Override
	public void setPublicKey(String publicKeyB64) {
		if (StringUtils.isEmpty(publicKeyB64)) {
			return;
		}
		try {
			byte[] buffer = CryptoUtil.unarmor(publicKeyB64);
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);

			KeyFactory keyFactory = CryptoUtil.getKeyFactory(algorithm, provider);
			this.publicKey = keyFactory.generatePublic(keySpec);
		} catch (InvalidKeySpecException e) {
			fail(e);
		}
	}

	/**
	 * Set the private key
	 *
	 * @param privateKeyB64 Base64 encoded private key text
	 */
	@Override
	public void setPrivateKey(String privateKeyB64) {
		if (StringUtils.isEmpty(privateKeyB64)) {
			return;
		}
		try {
			byte[] buffer = CryptoUtil.unarmor(privateKeyB64);
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);

			KeyFactory keyFactory = CryptoUtil.getKeyFactory(algorithm, provider);
			this.privateKey = keyFactory.generatePrivate(keySpec);
		} catch (InvalidKeySpecException e) {
			fail(e);
		}
	}

	/**
	 * Generate a random key
	 */
	@Override
	public void generateKey() {
		generateKey(DEFAULT_KEY_SIZE);
	}

	/**
	 * Encryption or decryption operations
	 *
	 * @param cipher Cipher object
	 * @param mode mode
	 * @param input Input buffer
	 * @return a new buffer containing the result
	 */
	@Override
	protected byte[] doFinal(Cipher cipher, int mode, byte[] input) {
		try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
			// java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block
			// Padding模式下,其中PKCS#1建议的Padding就占用了11个字节
			// In Padding mode, Padding, which is recommended by PKCS#1, occupies 11 bytes.
			final int keyLength = ((RSAPublicKey) publicKey).getModulus().bitLength();
			final int defaultBlockLength =
					(Cipher.DECRYPT_MODE == mode) ? (keyLength / 8) : (keyLength / 8 - 11);
			final int maxBlockLength =
					(cipher.getBlockSize() > 0) ? cipher.getBlockSize() : defaultBlockLength;
			int length = input.length;
			if (length <= maxBlockLength) {
				return cipher.doFinal(input);
			}

			int offSet = 0;
			byte[] cache;
			int i = 0;
			while (length - offSet > 0) {
				if (length - offSet <= maxBlockLength) {
					cache = cipher.doFinal(input, offSet, length - offSet);
				} else {
					cache = cipher.doFinal(input, offSet, maxBlockLength);
				}
				out.write(cache, 0, cache.length);
				i++;
				offSet = i * maxBlockLength;
			}
			return out.toByteArray();

		} catch (IllegalBlockSizeException | BadPaddingException | IOException e) {
			fail(e);
		}
		return new byte[0];
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy