java与openssl的rsa算法互

说明

   1.java生成的公私钥格式为 pkcs8, 而openssl默认生成的公私钥格式为 pkcs1,两者的密钥实际上是不能直接互用的

    2.java采用的rsa默认补齐方式是pkcs1, 因此互用的时候需要将openssl中的补齐方式设置为RSA_PKCS1_PADDING

    3.rsa加密中,加密数据长度有限制,不能超过密钥长度-11, 如密钥为1024位,则最长的加密数据位117字节; 加密后的密文长度总是为密钥的一半,即1024位的密文为512位

RSA加密常用的填充方式有下面3种: 1.RSA_PKCS1_PADDING 填充模式,最常用的模式 要求: 输入:必须 比 RSA 钥模长(modulus) 短至少11个字节, 也就是 RSA_size(rsa) – 11 如果输入的明文过长,必须切割, 然后填充 输出:和modulus一样长 根据这个要求,对于512bit的密钥, block length = 512/8 – 11 = 53 字节 2.RSA_PKCS1_OAEP_PADDING 输入:RSA_size(rsa) – 41 输出:和modulus一样长 3.for RSA_NO_PADDING  不填充 输入:可以和RSA钥模长一样长,如果输入的明文过长,必须切割, 然后填充 输出:和modulus一样长

Java的rsa封装

 代码如下,从网上copy下来的,在此源码中,需要注意的是

cipher = Cipher.getInstance("RSA")

    其中,这里可以选择rsa,也就默认了采用pkcs1补齐方式,也可以设置为其他的,如

cipher = Cipher.getInstance("RSA/ECB/NoPadding")

    另外加密的数据是byte格式,即无符号字符,因此常见的算法是利用base64编码,将byte格式的转为String,因此这里也涉及到java与openssl的base64编码相互转换的问题

    两者的输出格式是不同的,主要体现在换行的位置上,对openssl而言,base64编码后的换行主要是每64个出现一个换行;而java则是每76个字节出现一个换行,如果实际去测试,两者的base64编码解码是不能互用的。对于此,可以参考下面c的算法中的base64编码算法,屏蔽了换行的出现,这种情况下,java是可以解码openssl编码的结果的;相反,在openssl中,去掉换行后,也是可以处理java采用base64编码后的结果

import sun.misc.BASE64Encoder; 
import sun.misc.BASE64Decoder; 

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * RSA算法,实现数据的加密解密。
 * @author ShaoJiang
 *
 */
class RSAUtil {
	
	private static Cipher cipher;
	
	static{
		try {
			cipher = Cipher.getInstance("RSA"); // RSA/ECB/NoPadding
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 生成密钥对
	 * @param filePath 生成密钥的路径
	 * @return
	 */
	public static Map<String,String> generateKeyPair(String filePath){
		try {
			KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
			// 密钥位数
			keyPairGen.initialize(1024);
			// 密钥对
			KeyPair keyPair = keyPairGen.generateKeyPair();
			// 公钥
			PublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
			// 私钥
			PrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
			
			//得到公钥字符串
			String publicKeyString = getKeyString(publicKey);
			//得到私钥字符串
			String privateKeyString = getKeyString(privateKey);
			//将密钥对写入到文件
			FileWriter pubfw = new FileWriter(filePath+"/publicKey.keystore");
			FileWriter prifw = new FileWriter(filePath+"/privateKey.keystore");
			BufferedWriter pubbw = new BufferedWriter(pubfw);
			BufferedWriter pribw = new BufferedWriter(prifw);
			pubbw.write(publicKeyString);
			pribw.write(privateKeyString);
			pubbw.flush();
			pubbw.close();
			pubfw.close();
			pribw.flush();
			pribw.close();
			prifw.close();
			//将生成的密钥对返回
			Map<String,String> map = new HashMap<String,String>();
			map.put("publicKey",publicKeyString);
			map.put("privateKey",privateKeyString);
			return map;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 得到公钥
	 * 
	 * @param key
	 *            密钥字符串(经过base64编码)
	 * @throws Exception
	 */
	public static PublicKey getPublicKey(String key) throws Exception {
		byte[] keyBytes;
		keyBytes = (new BASE64Decoder()).decodeBuffer(key);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		return publicKey;
	}
	
	/**
	 * 得到私钥
	 * 
	 * @param key
	 *            密钥字符串(经过base64编码)
	 * @throws Exception
	 */
	public static PrivateKey getPrivateKey(String key) throws Exception {
		byte[] keyBytes;
		keyBytes = (new BASE64Decoder()).decodeBuffer(key);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}

	/**
	 * 得到密钥字符串(经过base64编码)
	 * 
	 * @return
	 */
	public static String getKeyString(Key key) throws Exception {
		byte[] keyBytes = key.getEncoded();
		String s = (new BASE64Encoder()).encode(keyBytes);
		return s;
	}   	
	
	/**
	 * 使用公钥对明文进行加密,返回BASE64编码的字符串
	 * @param publicKey
	 * @param plainText
	 * @return
	 */
	public static String encrypt(PublicKey publicKey,String plainText){
		try {			
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] enBytes = cipher.doFinal(plainText.getBytes());			
			return (new BASE64Encoder()).encode(enBytes);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 使用keystore对明文进行加密
	 * @param publicKeystore 公钥文件路径
	 * @param plainText      明文
	 * @return
	 */
	public static String encrypt(String publicKeystore,String plainText){
		try {			
			FileReader fr = new FileReader(publicKeystore);
			BufferedReader br = new BufferedReader(fr);
			String publicKeyString="";
			String str;
			while((str=br.readLine())!=null){
				publicKeyString+=str;
			}
			br.close();
			fr.close();
			cipher.init(Cipher.ENCRYPT_MODE,getPublicKey(publicKeyString));
			byte[] enBytes = cipher.doFinal(plainText.getBytes());			
			return (new BASE64Encoder()).encode(enBytes);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}	
	
	/**
	 * 使用私钥对明文密文进行解密
	 * @param privateKey
	 * @param enStr
	 * @return
	 */
	public static String decrypt(PrivateKey privateKey,String enStr){
		try {
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] deBytes = cipher.doFinal((new BASE64Decoder()).decodeBuffer(enStr));
			return new String(deBytes);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 使用keystore对密文进行解密
	 * @param privateKeystore  私钥路径
	 * @param enStr	                                     密文
	 * @return
	 */
	public static String decrypt(String privateKeystore,String enStr){
		try {
			FileReader fr = new FileReader(privateKeystore);
			BufferedReader br = new BufferedReader(fr);
			String privateKeyString="";
			String str;
			while((str=br.readLine())!=null){
				privateKeyString+=str;
			}
			br.close();
			fr.close();			
			cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKeyString));
			byte[] deBytes = cipher.doFinal((new BASE64Decoder()).decodeBuffer(enStr));
			return new String(deBytes);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}

public class Hello{

	// 将 s 进行 BASE64 编码 
	public static String getBASE64(String s) { 
		if (s == null) return null; 
		return (new sun.misc.BASE64Encoder()).encode( s.getBytes() ); 
	} 

	// 将 BASE64 编码的字符串 s 进行解码 
	public static String getFromBASE64(String s) { 
		if (s == null) return null; 
		BASE64Decoder decoder = new BASE64Decoder(); 
		try { 
		byte[] b = decoder.decodeBuffer(s); 
		return new String(b); 
		} catch (Exception e) { 
		return null; 
		} 
	}
	
	public static void testBASE64()
	{
		String s = "1234567887654321123456788765432112345678876543211234567887654321123456788765432112345678876543211234567887654321123456788765432112345678876543211234567887654321";
		System.out.println("length=" + s.length());
		String ans = getBASE64(s);
		System.out.println("length=" + ans.length());
		System.out.println(ans);
		String temp = "MTIzNDU2Nzg4NzY1NDMyMTEyMzQ1Njc4ODc2NTQzMjExMjM0NTY3ODg3NjU0MzIxMTIzNDU2Nzg4NzY1NDMyMTEyMzQ1Njc4ODc2NTQzMjE=";
		String res = getFromBASE64(temp);
		System.out.println(res);
		System.out.println("----------------------------------------");
	}
	
	public static void main(String[] args)
	{
		RSAUtil util = new RSAUtil();
		// util.generateKeyPair("key");
		String cp = "M04d2l9MyDiUUfAQ32FdphesAQJHZUk0dEsYQcU06IJo/RCF311GtJXBK1FhapITIvjkpsiz9NR25AGEFPdz4bs2o5/F0QIj5yFA+biLxgcFrDpd5gSWI1F8V7wbsl06tNLNOVihFfzl8xWbHMVqPhY3tj8Vu/QHEPPnx7mvHlc="; // cp保存的是由openssl加密后的结果(包括了对密文的base64编码)
		String cipher = util.encrypt("key/privateKey.keystore", "hello world");
		String recover = util.decrypt("key/publicKey.keystore", cp);
		System.out.println("cipher=" + cipher);
		System.out.println("recover=" + recover);		
	}
}

Openssl的rsa算法

  采用openssl的rsa算法实现公私钥加解密,这里由于项目需求,公私钥是使用java生成的,因此需要在密钥的首行和最后一行添加标记,两者对比如下:

--------java private key-------(本行不存在)
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKNQ3j+Ov9THQTMbNw+MwLOGRDwR
qkiH0QffSLBh1Nv6JHBp7yC07b+Nj0lMiBOjoMpk98W3RTdDuRcJ/ojM0OMPZWNiOdvrtJ7I/Haw
DiryMLqWR5gBCC0g+ODs2Cxr1ig5idNaX0bHy9ufSZpFd378OZLBVuOEBtQ7lnFhp/DxAgMBAAEC
gYEAiOBLFPvAHUZOh9XEZPzzuMLMR4gKrrVd5PonguTLsP5KMgknCMN7C3NKZwWEeulF5ruOyh/b
HAFfjEatFNyMKJnUhHwShvvSqncbZMBy9xmaA/FF0BUD285Vb+PhuPnL678KhEcKD3k99A+ym4qW
K9abeiJypAfvnleopBFV+c0CQQDcdUrMdCVCdUIxenIjz67Qp6672iBC2Ni5psow2SZZ9FTC31Z5
7jDowqrvsABbY7XbV8g1LUX/U6JLylXiz7MrAkEAvaU16YtUCdVe4s6saNLnQCfi2ykVdn5ovy3R
ZSn1gzQhy+//GFAhtUTjWO46zBicuNbJ1bNcaiF7DF4evU2OUwJBAJC14WqBlu+f3tpxoLjHG95V
I4qlrOWUR/bdd/1GnTkQ/A6K4c3Zv3saRXBeXG2g7v/TCFV3qWnncTJE18mxQs8CQQCPVxNDvaK8
eADrD2lzJY3SiRNHsWrekDcd4US24RsHm1y8J185gj+oIjRwoEfiweubLgWKN7JvKXU26OD1Fmyv
AkBR63yGMoIMo4AxLnkcr16j9WLBgQ/NXakPHcO2iMtFUsix3SNh96AkxZ+Fs87Ys70RuJOTtA/S
llTOdaKm5PVqpc

--------openssl private key-------(本行不存在)
-----BEGIN RSA PRIVATE KEY-----(存在)
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKIpKYdHzzjEaugD55bBNlV+iJ60
w+C2fecv2ptenw7lUqDRiXTQsMXUiEBPKB5MLtJhLgB9yiph+lIN/lv+7GcPHaEjLwvh0ZnwXiQ2
sbL9sCzvU9r/2otJJ+2NrEf0PA4wEocrSiEv3at7oD3PCVps8nht3fzuPYfCxWhkBXeXAgMBAAEC
gYAm/FZrm6wKLc618RpgeBsj+sPFxBfDkpw6VJrt95Wt8xwmZbnyR6n4JdyL+XvfrNkk4xA4NgXA
osWXrJ2WaHdU/J0C1NnVzwMSISojR3+w5nsY5xyfdhPCNthlWnlmYTXJNOaQUGVO3oR1q0be+drt
uQUV6yvsw/JDftskprqToQJBAOvObGbnz36YgdClJCVHZj3vFDlblAOiOFzIPq0hx72FpYcj/Ho3
3o5bAfZnHPMvOhbMaeY1xpm423f78qV2A+MCQQCwDDWM0uxvTA2XbpQGtVupZbqh/iZQ2eMYp8FJ
t4aa/brUesXZurqsHWcrM6HrWp7gA6DzYeSSy6cCeVV6dlO9AkBaW7JMSH3JO/Valz1fj5mNGAT+
6amxLsM8QntJ6ozYgdLpExAXYTtF/3ekDOUaBrnSrKfT0D13AFARDRlw7+UTAkAO7hokhUbT8Yk9
jH01THAnn58CWgF53eCqmJ+F1vCteFM97eOVoYZvTlcPjONwiFDtAqHFwkmWQXs6dHvRVPOpAkEA
jalQvMpQM7Ej3s2oK386LVrH/La0hZZ6Fn4bgCJ26YxB3AGN5J8uHLjU5oBUMxDefc0OraDdyStJ
pAh2vYzETw==
-----END RSA PRIVATE KEY-----

    下面是rsa的封装代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>

const char *RSA_SK = "privateKey.key";
const char *RSA_PK = "publicKey.key";
char *base64(const char *input, size_t length, char *result, size_t size)
{
	BIO * bmem = NULL;
	BIO * b64 = NULL;
	BUF_MEM * bptr = NULL;

	b64 = BIO_new(BIO_f_base64());
	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
	bmem = BIO_new(BIO_s_mem());
	b64 = BIO_push(b64, bmem);
	BIO_write(b64, input, length);
	BIO_flush(b64);
	BIO_get_mem_ptr(b64, &bptr);

	if(bptr->length + 1 > size)
	{
		BIO_free_all(b64);
		return NULL;
	}
	memcpy(result, bptr->data, bptr->length);
	result[bptr->length] = 0;

	BIO_free_all(b64);

	return result;
}

char *debase64(char *input, size_t length, char *result, size_t size)
{
	BIO * b64 = NULL;
	BIO * bmem = NULL;
	if(length > size)
		return NULL;
	memset(result, 0, size);

	b64 = BIO_new(BIO_f_base64());
	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
	bmem = BIO_new_mem_buf(input, length);
	bmem = BIO_push(b64, bmem);
	BIO_read(bmem, result, length);
	BIO_free_all(bmem);

	return result;
}

char *rsa_encrypt(const char *plain_text, char *result, size_t size, const char *pk_filename)
{
	unsigned char *cipher;
	int len;
	RSA *rsa;
	FILE *file;

	if (NULL == (file = fopen(pk_filename, "rb")))
	{
		fprintf(stderr, "%s public key file not exist!\n", pk_filename);
		return NULL ;
	}
	if (NULL == (rsa = PEM_read_RSA_PUBKEY(file, NULL, NULL, NULL )))
	{
		ERR_print_errors_fp(stdout);
		return NULL ;
	}
	fclose(file);

	len = RSA_size(rsa);
	if (NULL == (cipher = (unsigned char *) malloc(len + 1)))
	{
		RSA_free(rsa);
		return NULL ;
	}
	memset(cipher, 0, len + 1);

	if (0
			> RSA_public_encrypt(strlen(plain_text), (unsigned char *) plain_text,
					(unsigned char*) cipher, rsa, RSA_PKCS1_PADDING))// 这里设置填充方式,注意java和openssl的统一
	{
		RSA_free(rsa);
		free(cipher);
		return NULL ;
	}

	RSA_free(rsa);
	base64((char *) cipher, strlen((char *) cipher), result, size);
	free(cipher);
	return result;
}

char *rsa_decrypt(char *cipher, char *plain_text, size_t size, const char *sk_filename)
{
	FILE *file = NULL;
	RSA *rsa;
	int len;

	if (NULL == (file = fopen(sk_filename, "rb")))
	{
		fprintf(stderr, "%s private key file not exist!\n", sk_filename);
		return NULL ;
	}
	if ((rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL )) == NULL )
	{
		ERR_print_errors_fp(stdout);
		return NULL ;
	}
	fclose(file);

	len = RSA_size(rsa);
	memset(plain_text, 0, size);

	char temp[250];
	if(NULL == debase64(cipher, strlen(cipher), temp, 250))
	{
		RSA_free(rsa);
		fprintf(stderr, "decrypt error\n");
		return NULL;
	}

	if (0
			> RSA_private_decrypt(len, (unsigned char *) temp,
					(unsigned char*) plain_text, rsa, RSA_PKCS1_PADDING))
	{
		RSA_free(rsa);
		return NULL ;
	}

	RSA_free(rsa);
	return plain_text;
}

char *rsa_sign(const char *text, char *signature, size_t size, const char *sk_filename)
{
	RSA *rsa;
	FILE *file;
	unsigned char *sig;
	unsigned int sig_len;

	if (NULL == (file = fopen(sk_filename, "rb")))
	{
		printf("error:open key file error\n");
		return NULL ;
	}
	if ((rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL )) == NULL )
	{
		ERR_print_errors_fp(stdout);
		return NULL ;
	}
	fclose(file);

	if (NULL == (sig = (unsigned char*) malloc(RSA_size(rsa))))
	{
		RSA_free(rsa);
		return NULL ;
	}

	unsigned char temp[20];
	SHA((const unsigned char *) text, strlen(text), temp);
	if (1 != RSA_sign(NID_sha1, temp, 20, sig, &sig_len, rsa))
	{
		printf("error:fail to sign the message!\n");
		free(sig);
		RSA_free(rsa);
		return NULL ;
	}
	
	RSA_free(rsa);
	base64((char *) sig, strlen((char *) sig), signature, size);
	free(sig);
	return signature;
}

int rsa_verify(const char *text, char *sig, const char *pk_filename)
{
	RSA *rsa;
	FILE *file;

	if (NULL == (file = fopen(pk_filename, "rb")))
	{
		printf("error:open key file error\n");
		return -1;
	}
	if ((rsa = PEM_read_RSA_PUBKEY(file, NULL, NULL, NULL )) == NULL )
	{
		ERR_print_errors_fp(stdout);
		return -1;
	}
	fclose(file);

	unsigned char sig_temp[250];
	if(NULL == debase64(sig, strlen((char *) sig), sig_temp, 250))
	{
		fprintf(stderr, "verify debase error\n");
		return -1;
	}
	
	unsigned char temp[20];
	SHA((const unsigned char *) text, strlen(text), temp);
	int ret = RSA_verify(NID_sha1, temp, 20, (unsigned char *)sig_temp, 128, rsa);
	RSA_free(rsa);
	return (ret == 1) ? 0 : -1;
}


int main()
{
	char *temp = ",./qer/0qwertyui";
	char ans[500];
	rsa_encrypt(temp, ans, 500, RSA_PK);
	printf("cipher = %s\n", ans);

	char result[1024];
	rsa_decrypt(ans, result, 1024, RSA_SK);
	printf("recover = %s\n", result);
	
	
	char sig[1024];
	rsa_sign(temp, sig, 1024, RSA_SK);
	int v = rsa_verify(temp, sig, RSA_PK);
	printf("The v = %d\n", v);
	
	char *c = "SLaUQRk9rAkkoqve3cyo3DwX4Rd8IPYKCLb01tpW/i9444WptaDviD6J+NN03xlGF8MO0STdZ1wf3ZimBKcPwRz0ecHdNtWQ8ol4f3ZUo74x4oyDmtsLPI2yMDgsL0C5+GBnxWtUFPr4bJw+Uk4F78upnNx93dV8PNS+Q7MfArk="; // java加密后的结果
	char r[1024];
	rsa_decrypt(c, r, 1024, RSA_SK);
	printf("The r = %s--\n", r);
	
	char db[100];
	debase64(r, strlen(r), db, 100);
	int i = 0;
	while(i < strlen(db))
		printf("-%x", (unsigned char)db[i++]);
	printf("---%d--\n", strlen(db));	
	return 0;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

扫码关注云+社区

领取腾讯云代金券