使用RSA、MD5对参数生成签名与验签

在日常的工作中,我们对外提供的接口或调用三方的接口往往有一步生成签名或验签的步骤,这个步骤主要是验证调用方是

不是合法的以及内容是否被修改。比如:对于某些网上公开下载的软件,视频,尤其是镜像文件。如果被修改了可能会导致用不了

或者其他的问题,发布者镜像MD5算法计算一组数值。让下载的用户进行MD5数值对比,也就是MD5校验啦。由于MD5加密不可逆算,

如果数值一样,那就表示文件没有被修改的。反之,则被修改了。

接下来通过文字介绍、代码、运行结果的方式给大家介绍RSA、MD5生成签名和验签;

一、MD5签名与验签

1.MD5介绍

MD5全名Message-Digest Algorithm 5(信息-摘要算法)是一种不可逆的加密算法。

MD5算法具有以下特点:

1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。

2、容易计算:从原数据计算出MD5值很容易。

3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。

4、强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

MD5生成签名和验签需要MD5 key,这个key值就是一段字符串没有任何限制比如:123456ADSEF

2.签名与验签流程

首先参数放入一个字符串数组signFields,把参数和值放入一个对象或map中,使用JSONObject把这个对象转化成json对象。

然后构建签名原文,在构建签名原文时,我们需把参数按照字典(比如a,b,c)顺序排序,具体排序方法直接调java的Arrays.sort方法。

然后按照key=value的方式把所有参数和值拼接成字符串,多个参数直接以“&”符号隔开,再然后把MD5 key拼接在该签名原文的最后。

最后使用MD5Encrypt.getMessageDigest(signSrc)生成签名。

验签很简单,验签方按照上面的签名流程生成的签名与传过来的签名作对比如果相等就验签成功,否则验签失败。

3.具体代码如下:

需验签的参数map:

Map<String ,Object> map=new HashMap<String,Object>();
		map.put("name", "小明");
		map.put("age", 12);
		map.put("sex", "男");
		map.put("school", "xxx中学");
		map.put("address", "xxx小区");

MD5生成签名字符串:

/**
	 * MD5生成签名字符串
	 *
	 * @param map
	 *            需签名参数
	 * @param key
	 *            MD5key
	 * @return
	 */
	public static String MD5sign(Map<String, Object> map, String key) {
		String genSign = "";
		try {

			String[] signFields = new String[5];
			signFields[0] = "name";
			signFields[1] = "age";
			signFields[2] = "sex";
			signFields[3] = "school";
			signFields[4] = "address";
			JSONObject param = (JSONObject) JSONObject.toJSON(map);
			// 生成签名原文
			String signSrc = orgSignSrc(signFields, param);
			// MD5的方式签名
			signSrc += "&KEY=" + key;
			genSign = MD5Encrypt.getMessageDigest(signSrc);

		} catch (Exception e) {
			e.printStackTrace();
		}
		return genSign;
	}

构建签名原文:

/**
	 * 构建签名原文
	 *
	 * @param signFilds 参数列表
	 * @param param 参数与值的jsonbject
	 * @return
	 */
	private static String orgSignSrc(String[] signFields, JSONObject param) {
		if (signFields != null) {
			Arrays.sort(signFields); // 对key按照 字典顺序排序
		}

		StringBuffer signSrc = new StringBuffer("");
		int i = 0;
		for (String field : signFields) {
			signSrc.append(field);
			signSrc.append("=");
			signSrc.append((StringUtil.isEmpty(param.getString(field)) ? ""
					: param.getString(field)));
			// 最后一个元素后面不加&
			if (i < (signFields.length - 1)) {
				signSrc.append("&");
			}
			i++;
		}
		return signSrc.toString();
	}

MD5验证签名:

/**
	 * MD5验证签名
	 * @param map
	 * @param key
	 * @param sign
	 * @return
	 */
	public static void vlidateMD5sign(Map<String ,Object> map,String key,String sign) {
		String vsign=MD5sign(map, key);
		System.out.println("MD5验证签名生成的签名:"+vsign);
		System.out.println("MD5验证签名生成的签名与原签名是否一致:sign=vsign true?false:"+(vsign.equals(sign)));
	}

main方法:

public static void main(String[] args) {

		Map<String ,Object> map=new HashMap<String,Object>();
		map.put("name", "小明");
		map.put("age", 12);
		map.put("sex", "男");
		map.put("school", "xxx中学");
		map.put("address", "xxx小区");
		/***MD5签名与验签**/
		String key="123456ADSEF";
		String sign= MD5sign(map,key);
		System.out.println("生成的MD5签名:"+sign);
		vlidateMD5sign(map, key, sign) ;

	}

执行结果:

生成的MD5签名:A82ED0D0E0155D3926E0A6B6B3EE60C4
MD5验证签名生成的签名:A82ED0D0E0155D3926E0A6B6B3EE60C4
MD5验证签名生成的签名与原签名是否一致:sign=vsign true?false:true

二、RSA签名与验签

1.RSA介绍

RSA是目前最有影响力的公钥加密算法,该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对

其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。公钥是可发布的供任何人使用,

私钥则为自己所有,供解密之用。解密者拥有私钥,并且将由私钥计算生成的公钥发布给加密者。加密都使用公钥进行加密,并将密文发送

到解密者,解密者用私钥解密将密文解码为明文。

以甲要把信息发给乙为例,首先确定角色:甲为加密者,乙为解密者。首先由乙随机确定一个KEY,称之为密匙,将这个KEY始终保

存在机器B中而不发出来;然后,由这个 KEY计算出另一个KEY,称之为公匙。这个公钥的特性是几乎不可能通过它自身计算出生成它的私钥。

接下来通过网络把这个公钥传给甲,甲收到公钥后,利用公钥对信息加密,并把密文通过网络发送到乙,最后乙利用已知的私钥,就对密文进

行解码了。以上就是RSA算法的工作流程。

2.生成签名与验签流程

生成签名方:首先对参数放入一个字符串数组signFields,把参数和值放入一个对象或map中,使用JSONObject把这个对象转化成json对象。

然后构建签名原文,在构建签名原文时,我们需把参数按照字典(比如a,b,c)顺序排序,具体排序方法直接调java的Arrays.sort方法。 然后使用RSA

的私钥对签名原文进行签名。

验签方:和生产签名方一样先生成签名原文,然后使用RSA的公钥、生成签名方传入的签名及签名原文对生成签名方传入的签名进行验证,验

证结果为true说明验证成功,否则为未通过。

3.具体的代码实现

注:生成公钥和私钥可以使用RSA的相关工具也可以使用在线的web工具,网上工具很多的,一搜就出来了。我是用的是:http://web.chacuo.net/netrsakeypair这个在线工具。我采用的是密钥长度采用1024。

需验签的参数map:

Map<String ,Object> map=new HashMap<String,Object>();
		map.put("name", "小明");
		map.put("age", 12);
		map.put("sex", "男");
		map.put("school", "xxx中学");
		map.put("address", "xxx小区");

RSA公钥和私玥:

String prikey="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOq30rck7L3FshHVYWJK59sTToGMAn7WfYdrFN60AmPPyiMcIFXe3ZAxf7SWNbaQOPUz/xYr+oAXUBK17bykS/E2+Xa74wdN2VNbc7cZIggAjP9tGN0qhYTclbtC3pchcU8TVccrlVUN2lzJDLBHhPBDBFXzsQx9Vwtm2qjf2GcrAgMBAAECgYEAsHnz4aXOpkTNRSFVbiz5tLsIbNjTS4CDs1ysvWFE5rzls45DNa0yk2bUKPhDfHdli99DbO02FDbzCo5lKE+zlEHaC/WTp6guEe7jj5dwMl3shBZmgITCTk1/MQ46gGRG4RRADbQT/Y7tENp/GF3y9oJyJ+LmHFvfdEjSuY1/QzECQQD6aKqYFO8wuhLhy1fTvjMwlzok0szT9wTp+l6E7Ct9+csvdwaYjJrGsr6kUv+6YUwieSJ41lVtGnRy1oXEQG2TAkEA7/V35kYG+FMwYq/DOrBNaomRQGJVAOLzGRoK2dkjAkpoUAfzk4TTQ0KdJJ3T6mzF/6IQY+1oFDD42kNKJklfCQJARiya0i/bsC4VKI3RuRcuRUm8E6G3oRcym1d8sYd10MH1/QFAKfQNU+23m1lfLR4jNe34iSCXpBGr3JrdtdfQXQJAXgWRkGHZ800tRU3XMlTIULlMd6zP38QNOsWwgMGK7SfYjZs//opp+Q3N4v4QfedXAZ4vy+fHAzpZF7SMBkpzeQJALlMaKKeqKvPr8abXSRjW8u6s8tHaHX6CRV/1fGDX1bkUByqdFMO5CqIHn7isK2dHXI42bJVz63/d2Aax3lTbkA==";
		String pubkey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqt9K3JOy9xbIR1WFiSufbE06BjAJ+1n2HaxTetAJjz8ojHCBV3t2QMX+0ljW2kDj1M/8WK/qAF1ASte28pEvxNvl2u+MHTdlTW3O3GSIIAIz/bRjdKoWE3JW7Qt6XIXFPE1XHK5VVDdpcyQywR4TwQwRV87EMfVcLZtqo39hnKwIDAQAB";
		

生成RSA签名字符串:

/**
	 * RSA生成签名字符串
	 *
	 * @param map
	 *            需签名参数
	 * @param prikey
	 *            rsa私钥
	 * @return
	 */
	public static String RSAsign(Map<String, Object> map, String prikey) {
		String genSign = "";
		try {

			String[] signFields = new String[5];
			signFields[0] = "name";
			signFields[1] = "age";
			signFields[2] = "sex";
			signFields[3] = "school";
			signFields[4] = "address";
			JSONObject param = (JSONObject) JSONObject.toJSON(map);
			// 生成签名原文
			String src = orgSignSrc(signFields, param);
			genSign = RsaUtil.sign(src, prikey);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return genSign;
	}

构建签名原文:

/**
	 * 构建签名原文
	 *
	 * @param signFilds 参数列表
	 * @param param 参数与值的jsonbject
	 * @return
	 */
	private static String orgSignSrc(String[] signFields, JSONObject param) {
		if (signFields != null) {
			Arrays.sort(signFields); // 对key按照 字典顺序排序
		}

		StringBuffer signSrc = new StringBuffer("");
		int i = 0;
		for (String field : signFields) {
			signSrc.append(field);
			signSrc.append("=");
			signSrc.append((StringUtil.isEmpty(param.getString(field)) ? ""
					: param.getString(field)));
			// 最后一个元素后面不加&
			if (i < (signFields.length - 1)) {
				signSrc.append("&");
			}
			i++;
		}
		return signSrc.toString();
	}

RSA验证签名:

/**
	 * RSA验证签名
	 * @param map 参与验签的参数
	 * @param sign 签名者传入的签名
	 * @param publickey 公钥
	 * @return
	 */
	public static String vlidateRSAsign(Map<String, Object> map, String sign,
			String publickey) {
		String genSign = "";
		try {

			String[] signFields = new String[5];
			signFields[0] = "name";
			signFields[1] = "age";
			signFields[2] = "sex";
			signFields[3] = "school";
			signFields[4] = "address";
			JSONObject param = (JSONObject) JSONObject.toJSON(map);
			// 生成签名原文
			String signSrc = orgSignSrc(signFields, param);
			// 调用工具类验签
			boolean bool = RsaUtil.verify(signSrc, sign, publickey);
			System.out.println("验证签名生成的签名与原签名是否一致: true?false:" + bool);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return genSign;
	}

main方法:

public static void main(String[] args) {

		Map<String ,Object> map=new HashMap<String,Object>();
		map.put("name", "小明");
		map.put("age", 12);
		map.put("sex", "男");
		map.put("school", "xxx中学");
		map.put("address", "xxx小区");

		/***RSA签名与验签**/
		String prikey="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOq30rck7L3FshHVYWJK59sTToGMAn7WfYdrFN60AmPPyiMcIFXe3ZAxf7SWNbaQOPUz/xYr+oAXUBK17bykS/E2+Xa74wdN2VNbc7cZIggAjP9tGN0qhYTclbtC3pchcU8TVccrlVUN2lzJDLBHhPBDBFXzsQx9Vwtm2qjf2GcrAgMBAAECgYEAsHnz4aXOpkTNRSFVbiz5tLsIbNjTS4CDs1ysvWFE5rzls45DNa0yk2bUKPhDfHdli99DbO02FDbzCo5lKE+zlEHaC/WTp6guEe7jj5dwMl3shBZmgITCTk1/MQ46gGRG4RRADbQT/Y7tENp/GF3y9oJyJ+LmHFvfdEjSuY1/QzECQQD6aKqYFO8wuhLhy1fTvjMwlzok0szT9wTp+l6E7Ct9+csvdwaYjJrGsr6kUv+6YUwieSJ41lVtGnRy1oXEQG2TAkEA7/V35kYG+FMwYq/DOrBNaomRQGJVAOLzGRoK2dkjAkpoUAfzk4TTQ0KdJJ3T6mzF/6IQY+1oFDD42kNKJklfCQJARiya0i/bsC4VKI3RuRcuRUm8E6G3oRcym1d8sYd10MH1/QFAKfQNU+23m1lfLR4jNe34iSCXpBGr3JrdtdfQXQJAXgWRkGHZ800tRU3XMlTIULlMd6zP38QNOsWwgMGK7SfYjZs//opp+Q3N4v4QfedXAZ4vy+fHAzpZF7SMBkpzeQJALlMaKKeqKvPr8abXSRjW8u6s8tHaHX6CRV/1fGDX1bkUByqdFMO5CqIHn7isK2dHXI42bJVz63/d2Aax3lTbkA==";
		String pubkey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqt9K3JOy9xbIR1WFiSufbE06BjAJ+1n2HaxTetAJjz8ojHCBV3t2QMX+0ljW2kDj1M/8WK/qAF1ASte28pEvxNvl2u+MHTdlTW3O3GSIIAIz/bRjdKoWE3JW7Qt6XIXFPE1XHK5VVDdpcyQywR4TwQwRV87EMfVcLZtqo39hnKwIDAQAB";
		String rsaSign= RSAsign(map,prikey);
		System.out.println("生成的RSA签名:"+rsaSign);
		vlidateRSAsign(map, rsaSign, pubkey) ;

	}

执行结果:

生成的RSA签名:6AFF1E6A6CE17516D56ED94999E24FC6169290E111E207C4D9EFA57DA04525D173032FE32B620D16335164226420D0EDEE5EE5F9C9B413DAF2B7F418AE4EA17E055D718B1C1CB188A9BBBE1C5CF559C0BD5CADF83468D62C29635EF7CDE6B6AF0D63137A8FDA3CB26996DFBA3C505EDC04A843224AD1BBCA34ACD80EF7C3C5CA
验证签名生成的签名与原签名是否一致: true?false:true

以上就是MD5、RSA签名与验签的介绍。

注:关于本文使用的MD5Encrypt、RsaUtil类文件及相关的jar包,由于代码比较多,在这里就写上去了。我直接把demo源码上传到我的空间,大家可以免费下载。地址如下:

http://download.csdn.net/detail/mr_smile2014/9596252

时间: 2024-11-20 11:30:17

使用RSA、MD5对参数生成签名与验签的相关文章

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

重要的事情说三遍,该篇文章主要是验证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 下

RSA后台签名前台验签的应用(前台采用jsrsasign库)

写在前面 安全测试需要, 为防止后台响应数据返给前台过程中被篡改前台再拿被篡改后的数据进行接下来的操作影响正常业务, 决定采用RSA对响应数据进行签名和验签, 于是有了这篇<RSA后台签名前台验签的应用>. 我这里所谓的返给前台的数据只是想加密用户验证通过与否的字段success是true还是false, 前台拿这个success作为判断依据进行下一步的操作, 是进一步向后台发起请求还是直接弹出错误消息.照测试结果看这是个逻辑漏洞, 即使后台返回的是false, 在返回前台的过程中响应包被劫获

.NET RSA解密、签名、验签

using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; namespace API.Tools { /// <summary> /// 类名:RSAFromPkcs8 /// 功能:RSA解密.签名.验签 /

java/php/c#版rsa签名以及验签实现

本文为转载,请转载请注明地址: 原文地址为        http://xw-z1985.iteye.com/blog/1837376 在开放平台领域,需要给isv提供sdk,签名是Sdk中需要提供的功能之一.由于isv使用的开发语言不是单一的,因此sdk需要提供多种语言的版 本.譬如java.php.c#.另外,在电子商务尤其是支付领域,对安全性的要求比较高,所以会采用非对称密钥RSA 本文主要介绍如何基于java.php.c#在客户端使用rsa签名,然后在服务端使用Java验签. 基于ope

关于rsa非对称加密、解密、签名、验签

测试数据: 1 var xmlprikey =""; 2 var xmlpubkey =""; 3 rsa = new RSACryption(); 4 //待处理字符串 5 var str="hello成功啊啊!¥%……&*([email protected]#$%^&*()@#$%^&*()_}::{>>?}{>?{?"; 6 var strlen= str.Length; 7 rsa.RSAKey(

java rsa 签名,验签

package com.fabiao; import java.security.KeyFactory;import java.security.MessageDigest;import java.security.PrivateKey;import java.security.PublicKey;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec; import o

用Java实现RSA加解密及签名和验签(1)——.pem文件格式秘钥

一.***.pem文件格式的秘钥(获取秘钥:可通过文件读取内容或者直接打开文件复制内容),我这里是打开文件复制秘钥直接使用 1.准备秘钥对,通过openssl生成秘钥对,生成秘钥可参考:https://www.cnblogs.com/ouyanxia/p/12427955.html A_RSA_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDnPzYKf20JIza

用Java实现RSA加解密及签名和验签(2)——.pfx文件格式秘钥

注:.pfx 主要用于windows平台,浏览器可以使用,也是包含证书和私钥,获取私钥需要密码才可以 .pfx文件生成的方式可参考:https://www.cnblogs.com/ouyanxia/p/12427955.html 1.准备好pfx秘钥文件(alias默认是1) path=/RSA/other/openssl.pfx pwd=秘钥的秘钥(生成秘钥时记得存好) alias=1 cerPath=/RSA/other/openssl.cer 2.编写RSAUtil import java

NodeJs支付宝移动支付签名及验签

非常感谢 :http://www.jianshu.com/p/8513e995ff3a?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=weibo 的文章,如果不是找到这篇文章我可能还要继续坑几天,代码也基本都是照着他的搬过来的,不过支付宝移动支付文档写的非常糟糕而且没有node的SDK和demo,写起来异常痛苦..好在找到了这篇文章顺便折腾了一下午支付宝的技术人员总算把移动支付整个流程给做