RSA加密、解密、签名、验签 DSA签名、验签

C# 同时被 3 个专栏收录
103 篇文章 5 订阅
6 篇文章 1 订阅
9 篇文章 1 订阅

重要的事情说三遍,该篇文章主要是验证JAVA的RSA签名、验签的测试代码,主要代码参考 http://xw-z1985.iteye.com/blog/1837376

重要的事情说三遍,该篇文章主要是验证JAVA的RSA签名、验签的测试代码,主要代码参考 http://xw-z1985.iteye.com/blog/1837376

重要的事情说三遍,该篇文章主要是验证JAVA的RSA签名、验签的测试代码,主要代码参考 http://xw-z1985.iteye.com/blog/1837376

下面是C#版的RSA、DSA代码

    using System.Security.Cryptography;
    public class AsymmetricAlgorithmHelper<T>
        where T : AsymmetricAlgorithm, new()
    {
        protected static TResult Execute<TResult>(string key, Func<T, TResult> func)
        {
            using (T algorithm = new T())
            {
                algorithm.FromXmlString(key);
                return func(algorithm);
            }
        }
        /// <summary>
        /// 按默认规则生成公钥、私钥
        /// </summary>
        /// <param name="publicKey">公钥(Xml格式)</param>
        /// <param name="privateKey">私钥(Xml格式)</param>
        public static void Create(out string publicKey, out string privateKey)
        {
            KeyGenerator.CreateAsymmetricAlgorithmKey<T>(out publicKey, out privateKey);
        }
    }
    public class RSAHelper : AsymmetricAlgorithmHelper<RSACryptoServiceProvider>
    {
        /// <summary>
        /// RSA加密
        /// </summary>
        /// <param name="publickey">公钥</param>
        /// <param name="content">加密前的原始数据</param>
        /// <param name="fOAEP">如果为 true,则使用 OAEP 填充(仅在运行 Microsoft Windows XP 或更高版本的计算机上可用)执行直接的 System.Security.Cryptography.RSA加密;否则,如果为 false,则使用 PKCS#1 1.5 版填充。</param>
        /// <returns>加密后的结果(base64格式)</returns>
        public static string Encrypt(string publickey, string content, bool fOAEP = false)
        {
            return Execute(publickey,
                algorithm => Convert.ToBase64String(algorithm.Encrypt(Encoding.UTF8.GetBytes(content), fOAEP)));
        }
        /// <summary>
        /// RSA解密
        /// </summary>
        /// <param name="privatekey">私钥</param>
        /// <param name="content">加密后的内容(base64格式)</param>
        /// <param name="fOAEP">如果为 true,则使用 OAEP 填充(仅在运行 Microsoft Windows XP 或更高版本的计算机上可用)执行直接的 System.Security.Cryptography.RSA加密;否则,如果为 false,则使用 PKCS#1 1.5 版填充。</param>
        /// <returns></returns>
        public static string Decrypt(string privatekey, string content, bool fOAEP = false)
        {
            return Execute(privatekey,
                algorithm => Encoding.UTF8.GetString(algorithm.Decrypt(Convert.FromBase64String(content), fOAEP)));
        }
        /// <summary>
        /// RSA签名
        /// </summary>
        /// <param name="privatekey">私钥</param>
        /// <param name="content">需签名的原始数据(utf-8)</param>
        /// <param name="halg">签名采用的算法,如果传null,则采用MD5算法</param>
        /// <returns>签名后的值(base64格式)</returns>
        public static string SignData(string privatekey, string content, object halg = null)
        {
            return Execute(privatekey,
                algorithm => Convert.ToBase64String(algorithm.SignData(Encoding.UTF8.GetBytes(content), GetHalg(halg))));
        }
        /// <summary>
        /// RSA验签
        /// </summary>
        /// <param name="publicKey">公钥</param>
        /// <param name="content">需验证签名的数据(utf-8)</param>
        /// <param name="signature">需验证的签名字符串(base64格式)</param>
        /// <param name="halg">签名采用的算法,如果传null,则采用MD5算法</param>
        /// <returns></returns>
        public static bool VerifyData(string publicKey, string content, string signature, object halg = null)
        {
            return Execute(publicKey,
                algorithm => algorithm.VerifyData(Encoding.UTF8.GetBytes(content), GetHalg(halg), Convert.FromBase64String(signature)));
        }
        private static object GetHalg(object halg)
        {
            if (halg == null)
            {
                halg = "MD5";
            }
            return halg;
        }
        /// <summary>
        /// 生成公钥、私钥
        /// </summary>
        /// <param name="publicKey">公钥(Xml格式)</param>
        /// <param name="privateKey">私钥(Xml格式)</param>
        /// <param name="keySize">要生成的KeySize,支持的MinSize:384 MaxSize:16384 SkipSize:8</param>
        public static void Create(out string publicKey, out string privateKey, int keySize = 1024)
        {
            RSACryptoServiceProvider provider = new RSACryptoServiceProvider(keySize);
            KeyGenerator.CreateAsymmetricAlgorithmKey(out publicKey, out privateKey, provider);
        }
    } 
    public class DSAHelper : AsymmetricAlgorithmHelper<DSACryptoServiceProvider>
    {
        /// <summary>
        /// DSA签名
        /// </summary>
        /// <param name="privatekey">私钥</param>
        /// <param name="content">需签名的原始数据(utf-8)</param>
        /// <returns>签名后的值(base64格式)</returns>
        public static string SignData(string privatekey, string content)
        {
            return Execute(privatekey,
                algorithm => Convert.ToBase64String(algorithm.SignData(Encoding.UTF8.GetBytes(content))));
        }
        /// <summary>
        /// DSA验签
        /// </summary>
        /// <param name="publicKey">公钥</param>
        /// <param name="content">需验证签名的数据(utf-8)</param>
        /// <param name="signature">需验证的签名字符串(base64格式)</param>
        /// <returns></returns>
        public static bool VerifyData(string publicKey, string content, string signature)
        {
            return Execute(publicKey,
                algorithm => algorithm.VerifyData(Encoding.UTF8.GetBytes(content), Convert.FromBase64String(signature)));
        }
        /// <summary>
        /// 生成公钥、私钥
        /// </summary>
        /// <param name="publicKey">公钥(Xml格式)</param>
        /// <param name="privateKey">私钥(Xml格式)</param>
        /// <param name="keySize">要生成的KeySize,支持的MinSize:512 MaxSize:1024 SkipSize:64</param>
        public static void Create(out string publicKey, out string privateKey, int keySize = 1024)
        {
            DSACryptoServiceProvider provider = new DSACryptoServiceProvider(keySize);
            KeyGenerator.CreateAsymmetricAlgorithmKey(out publicKey, out privateKey, provider);
        }
    }

C#下的测试代码,RSAConverter的代码地址为 C#下解析、生成JAVA的RSA密钥、公钥_sky 胡萝卜星星-CSDN博客

        static void RSADemo()
        {
            string publicJavaKey, privateJavaKey, content, publicCSharpKey, privateCSharpKey, signData;
            //java的base64格式秘钥
            privateJavaKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMsNFZUmKwtwFH271JMbjuMslL2C4Dw5iYps/jkXu5vxhYzNaKMA5Bu2Adlhw2FzA/fapglWDN68/8OG1veX0M9C/5YhigsIdhzixi6WrkMFfqp/nZhcRgcm900P0UM1wAceemPEvU7+uq9bSrMJWxwSmcryP63KKtCZcFfW05u9AgMBAAECgYBIiisctp8IHglkBddimqTIaePVdE0RluiZKGkGEoF2q6kvbS6llSro73PnqjJ3vPQ89sL8cN52MIUa4DAqEfWJgtl/cy2RKK64ajESZadIQnW2F2Whsuob/T1wEv05jQeej4qUdVp5yz1lhWvwlwoB3BLWPwhnReg87OS8jFFQLQJBAPEA0kv1OIhlQx1ew1WEqd8mK2VbtmLDOwZL4uZvDkx7/dtthVxNw25cVfJM6V9AET2j9Jbyt2pHibfjf1fICmMCQQDXr6+yfl7yLOVDiM4lQFH7if03GsJsfvizvUyoI6suumyTFhjfkDyL3JM4flyWDpFPN76b9TDpjaz4pY1KfItfAkBG0ZD6VRLJscfpB4GqzZMFSbgSzsJnfysHDKGeSSAQhZbxNdusZgV5lpSC4Orq3G60iEtFWAlhp6fma2luKBA1AkEArS3OR+Y5u/+aUcBtrPFZIjvoia89vrmwXTk4bKS/FPTwqqUKca8xPidsOecT1hR6Tf33WOflTxHHeZoLuWwIxwJAZQ4fS9Gatxyn+3ubXxltbyKxpYhfwEP1JvIQqOACtKLXBjWoYzdnUO2jr6WZ2UBeaDCqzA30VGmjG7pud94ZhA==";
            publicJavaKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLDRWVJisLcBR9u9STG47jLJS9guA8OYmKbP45F7ub8YWMzWijAOQbtgHZYcNhcwP32qYJVgzevP/Dhtb3l9DPQv+WIYoLCHYc4sYulq5DBX6qf52YXEYHJvdND9FDNcAHHnpjxL1O/rqvW0qzCVscEpnK8j+tyirQmXBX1tObvQIDAQAB";
            content = "测试数据你好";
            //转成C#的xml格式
            publicCSharpKey = RSAConverter.RSAPublicKeyJava2DotNet(publicJavaKey);
            privateCSharpKey = RSAConverter.RSAPrivateKeyJava2DotNet(privateJavaKey);
            Console.WriteLine("转换得到的C#公钥:" + publicCSharpKey);
            Console.WriteLine("转换得到的C#私钥:" + privateCSharpKey);

            //RSAHelper.Create(out publicCSharpKey, out privateCSharpKey, 1024);
            string encData = RSAHelper.Encrypt(publicCSharpKey, content);
            Console.WriteLine("公钥加密结果:" + encData);
            Console.WriteLine("私钥解密结果:" + RSAHelper.Decrypt(privateCSharpKey, encData));
            //下面是java通过SHA1WithRSA生成的签名
            //Dv67xT5SgGQ9q+bKVWuyyxljx28cxNkIMDk5ro8cMopsiPf7Z8/n/02yaN/SVUQPmWJk/f+cjwydikVStwjkll49/D4PrTW+nd4XWr5hea8n7c6JTdRvaOGwFG3Do1n8Sndj7aqxuUWUmlLiC1dYEHeZhSwm9BCMJJSvF8n34CY=
            //下面是JAVA通过MD5withRSA生成的签名
            //MUXPVxxNZOlzDY03hOXQgQLQnJ/SrJa0lxQAx8Kl+H+pLBcL6cqdLupVwK6mwKZ1mRP2CCwGaQC8wHkOVRafPdkOSRsnKnkAjRv1iqHBxJtPCG83XlrB7AofzqHi/VULCA9KdWqmvnarVCV+lVwwUVCXP5cK1nwEJN258T/eV8M=
            //下面是JAVA通过SHA256WithRSA生成的签名
            //qPfkIAITcKW452/NacSQHjNbBUtJNhel4SpTMp1T/nGaY0Z4I3Xx13/aVl001ZKwBfdFf7cIPAKlbqmywm3sqEzVpBQlVOYMZBARlHAoOexTCZk50tgrCFUlXXa2pWt+jRS2lGUX5esbo6cKS0Yk1fdkYlm+4S4NRKYgEAXO+lY=
            string halg = "SHA256";//SHA1 MD5 SHA256
            signData = RSAHelper.SignData(privateCSharpKey, content, halg);//SHA1
            Console.WriteLine("生成签名:" + signData);
            Console.WriteLine("签名一致:" + RSAHelper.VerifyData(publicCSharpKey, content, signData, halg));
        }
        static void DSADemo()
        {
            string publicKey, privateKey;
            DSAHelper.Create(out publicKey, out privateKey);
            string content = "测试数据";
            string signData = DSAHelper.SignData(privateKey, content);
            Console.WriteLine("生成签名:" + signData);
            Console.WriteLine("签名一致:" + DSAHelper.VerifyData(publicKey, content, signData));
        }


然后是JAVA版的代码,注意与参考地址代码基本相同,只是调整了Hash算法传递,同时包含了测试代码

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

public class Test {

	private static String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMsNFZUmKwtwFH271JMbjuMslL2C4Dw5iYps/jkXu5vxhYzNaKMA5Bu2Adlhw2FzA/fapglWDN68/8OG1veX0M9C/5YhigsIdhzixi6WrkMFfqp/nZhcRgcm900P0UM1wAceemPEvU7+uq9bSrMJWxwSmcryP63KKtCZcFfW05u9AgMBAAECgYBIiisctp8IHglkBddimqTIaePVdE0RluiZKGkGEoF2q6kvbS6llSro73PnqjJ3vPQ89sL8cN52MIUa4DAqEfWJgtl/cy2RKK64ajESZadIQnW2F2Whsuob/T1wEv05jQeej4qUdVp5yz1lhWvwlwoB3BLWPwhnReg87OS8jFFQLQJBAPEA0kv1OIhlQx1ew1WEqd8mK2VbtmLDOwZL4uZvDkx7/dtthVxNw25cVfJM6V9AET2j9Jbyt2pHibfjf1fICmMCQQDXr6+yfl7yLOVDiM4lQFH7if03GsJsfvizvUyoI6suumyTFhjfkDyL3JM4flyWDpFPN76b9TDpjaz4pY1KfItfAkBG0ZD6VRLJscfpB4GqzZMFSbgSzsJnfysHDKGeSSAQhZbxNdusZgV5lpSC4Orq3G60iEtFWAlhp6fma2luKBA1AkEArS3OR+Y5u/+aUcBtrPFZIjvoia89vrmwXTk4bKS/FPTwqqUKca8xPidsOecT1hR6Tf33WOflTxHHeZoLuWwIxwJAZQ4fS9Gatxyn+3ubXxltbyKxpYhfwEP1JvIQqOACtKLXBjWoYzdnUO2jr6WZ2UBeaDCqzA30VGmjG7pud94ZhA==";
	private static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLDRWVJisLcBR9u9STG47jLJS9guA8OYmKbP45F7ub8YWMzWijAOQbtgHZYcNhcwP32qYJVgzevP/Dhtb3l9DPQv+WIYoLCHYc4sYulq5DBX6qf52YXEYHJvdND9FDNcAHHnpjxL1O/rqvW0qzCVscEpnK8j+tyirQmXBX1tObvQIDAQAB";
	private static String algorithm="SHA256WithRSA";//MD5withRSA  SHA1WithRSA SHA256WithRSA
	
	public static void main(String[] args) {
		Test run1 = new Test();
		try {
			String sign = run1.rsaSign("测试数据你好", privateKey, "utf-8", algorithm);
			System.out.println(sign);
			boolean bRet = run1.doCheck("测试数据你好", sign, publicKey, "utf-8", algorithm);
			System.out.println(bRet);
		} catch (SignatureException e) {
			e.printStackTrace();
		}
	}

	public String rsaSign(String content, String privateKey, String charset, String algorithm) throws SignatureException {
		try {
			PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", new ByteArrayInputStream(privateKey.getBytes()));

			Signature signature = Signature.getInstance(algorithm);//MD5withRSA  SHA1WithRSA SHA256WithRSA
			signature.initSign(priKey);
			if (StringUtils.isEmpty(charset)) {
				signature.update(content.getBytes());
			} else {
				signature.update(content.getBytes(charset));
			}
			byte[] signed = signature.sign();
			return new String(Base64.encodeBase64(signed));
		} catch (Exception e) {
			throw new SignatureException("RSAcontent = " + content + "; charset = " + charset, e);
		}
	}

	boolean doCheck(String content, String sign, String publicKey, String charset, String algorithm) throws SignatureException {
		try {
			PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));

			Signature signature = Signature.getInstance(algorithm);//MD5withRSA  SHA1WithRSA SHA256WithRSA
			signature.initVerify(pubKey);
			byte[] encodedKey = content.getBytes(charset);
			signature.update(encodedKey);
			// signature.update(getContentBytes(content, charset));
			return signature.verify(Base64.decodeBase64(sign.getBytes()));
		} catch (Exception e) {
			throw new SignatureException(
					"RSA验证签名[content = " + content + "; charset = " + charset + "; signature = " + sign + "]发生异常!", e);
		}
	}

	private PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) throws NoSuchAlgorithmException {
		try {
			KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

			StringWriter writer = new StringWriter();
			// StreamUtil.io(new InputStreamReader(ins), writer);
			// byte[] encodedKey = writer.toString().getBytes();
			byte[] encodedKey = IOUtils.toByteArray(ins);
			// 先base64解码
			encodedKey = Base64.decodeBase64(encodedKey);
			return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
		} catch (IOException ex) {
			// 不可能发生
		} catch (InvalidKeySpecException ex) {
			// 不可能发生
		}
		return null;
	}

	public PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception {
		if (ins == null || StringUtils.isEmpty(algorithm)) {
			return null;
		}

		KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
		byte[] encodedKey = IOUtils.toByteArray(ins);

		encodedKey = Base64.decodeBase64(encodedKey);
		return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
	}
}

KeyGenerator源码地址:C#下对称算法、非对称算法生成秘钥_sky 胡萝卜星星-CSDN博客

  • 0
    点赞
  • 6
    评论
  • 3
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值