RSA加密算法耗時耗在哪裏?

結論1:密鑰生成佔據初始化99%的時間

	public void createKeys(int keySize) throws Exception {
		long t1 = System.currentTimeMillis();
		KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
		kpg.initialize(keySize);
		long t2 = System.currentTimeMillis();
		KeyPair keyPair = kpg.generateKeyPair();
		long t3 = System.currentTimeMillis();
		this.publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
		this.privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
		this.rsaPublicKey = this.getPublicKey(this.publicKey);
		this.rsaPrivateKey = this.getPrivateKey(this.privateKey);
		long t4 = System.currentTimeMillis();
		System.out.printf("Total Time: %d ms, key generation time: %d ms.\n", t4 - t1, t3 - t2);
	}

經測試發現,創建密鑰的過程中,密鑰對的生成算法佔據了99%的時間,如下所示,總時間1788ms,而創建密鑰對就用了1768ms。這個過程雖然耗時很長,但是好在只需要一次創建,可以重複使用。

Total Time: 1788 ms, key generation time: 1768 ms.

結論2:加密耗時佔據99%的時間

第二個耗時的地方是加密,以下代碼

	public static void main(String[] args) throws Exception {
		String str = "This is what I wanted to tell you.";
		long[] times = new long[4];
		times[0] = System.currentTimeMillis();
		RSAUtil rsa = new RSAUtil();
		times[1] = System.currentTimeMillis();
		String encodedData = rsa.publicEncrypt(str);
		times[2] = System.currentTimeMillis();
		String decodedData = rsa.privateDecrypt(encodedData);
		times[3] = System.currentTimeMillis(); 
		for (int i = 0; i < times.length - 1; i++)
			System.out.println(i + ":  " + (times[i + 1] - times[i]) + " ms.");
	}

測試結果爲:

0:  16 ms.
1:  1572 ms.
2:  8 ms.

這個過程表明加密是耗時的,解密是很快速的。所以RSA算法主要的使用場景是爲了生成密鑰,而不是爲了數據加解密,因爲其所消耗的時間太多,不適合頻繁使用。

附:源代碼

package test;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import java.util.ArrayList;
import java.util.Base64;

public class RSAUtil {
	public static final String charset = "UTF-8";
	public static final String algorithm = "RSA";
	public String publicKey = null;
	public String privateKey = null;
	public RSAPublicKey rsaPublicKey = null;
	public RSAPrivateKey rsaPrivateKey = null;

	public RSAUtil() throws Exception {
		createKeys(1024);
	}

	public void createKeys(int keySize) throws Exception {
		KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
		kpg.initialize(keySize);
		KeyPair keyPair = kpg.generateKeyPair();
		this.publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
		this.privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
		this.rsaPublicKey = this.getPublicKey(this.publicKey);
		this.rsaPrivateKey = this.getPrivateKey(this.privateKey);
	}

	private RSAPublicKey getPublicKey(String publicKey) throws Exception {
		KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));
		return (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
	}

	private RSAPrivateKey getPrivateKey(String privateKey) throws Exception {
		KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
		return (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
	}

	public String publicEncrypt(String data) throws Exception {
		Cipher cipher = Cipher.getInstance(algorithm);
		cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
		return Base64.getEncoder().encodeToString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(charset),
				rsaPublicKey.getModulus().bitLength()));
	}

	public String privateDecrypt(String data) throws Exception {
		Cipher cipher = Cipher.getInstance(algorithm);
		cipher.init(Cipher.DECRYPT_MODE, rsaPrivateKey);
		return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.getDecoder().decode(data),
				rsaPrivateKey.getModulus().bitLength()), charset);
	}

	public String privateEncrypt(String data, RSAPrivateKey privateKey) throws Exception {
		Cipher cipher = Cipher.getInstance(algorithm);
		cipher.init(Cipher.ENCRYPT_MODE, privateKey);
		return Base64.getEncoder().encodeToString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(charset),
				privateKey.getModulus().bitLength()));
	}

	public String publicDecrypt(String data, RSAPublicKey publicKey) throws Exception {
		Cipher cipher = Cipher.getInstance(algorithm);
		cipher.init(Cipher.DECRYPT_MODE, publicKey);
		return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.getDecoder().decode(data),
				publicKey.getModulus().bitLength()), charset);
	}

	private byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) throws Exception {
		int maxBlock = opmode == Cipher.DECRYPT_MODE ? keySize / 8 : keySize / 8 - 11;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0, i = 0;
		byte[] buff;
		while (datas.length > offSet) {
			buff = datas.length - offSet > maxBlock ? cipher.doFinal(datas, offSet, maxBlock)
					: cipher.doFinal(datas, offSet, datas.length - offSet);
			out.write(buff, 0, buff.length);
			offSet = ++i * maxBlock;
		}
		return out.toByteArray();
	}

	public static void main(String[] args) throws Exception {
		String str = "This is what I wanted to tell you.";
		long[] times = new long[4];
		times[0] = System.currentTimeMillis();
		RSAUtil rsa = new RSAUtil();
		times[1] = System.currentTimeMillis();
		String encodedData = rsa.publicEncrypt(str);
		times[2] = System.currentTimeMillis();
		String decodedData = rsa.privateDecrypt(encodedData);
		times[3] = System.currentTimeMillis();

		System.out.println("Original:  " + str);
		System.out.println("PubKey: " + rsa.publicKey);
		System.out.println("PriKey: " + rsa.privateKey);
//		System.out.println("RsaPubKey: " + rsa.rsaPublicKey);
//		System.out.println("RsaPriKey: " + rsa.rsaPrivateKey);
		System.out.println("Encoded:   " + encodedData);
		System.out.println("Decoded:   " + decodedData);
		for (int i = 0; i < times.length - 1; i++)
			System.out.println("All Time:  " + (times[i + 1] - times[i]) + " ms.");
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章