.net程序集强名称签名实践
- 格式:doc
- 大小:465.00 KB
- 文档页数:13
.Net解决引⽤程序集没有强名称报错⽬录⼀、什么是强名称为什么要使⽤强名称签名⼆、如何设置强名称1、应⽤程序有源代码1、⽣成公钥2、设置签名公钥2、应⽤程序没有源代码1、打开SDK命令提⽰窗⼝2、创建⼀个新的随机密钥对3、反编译⽬标程序集4、重新编译,附带强命名参数5、验证签名信息6、重新引⽤⼀、什么是强名称强名称是⼀个由程序集的标识组成并通过公钥和数字签名(针对该程序集⽣成)加强的名称,其中的标识包括程序集的简单⽂本名称、版本号和区域性信息。
由于程序集清单包含构成程序集实现的所有⽂件的⽂件散列,因此只对程序集中包含程序集清单的⼀个⽂件⽣成数字签名就⾜够了。
强名称相同的程序集应该是相同的。
为什么要使⽤强名称签名通过签发具有强名称的程序集,您可以确保名称的全局唯⼀性。
强名称还特别满⾜以下要求:强名称依赖于唯⼀的密钥对来确保名称的唯⼀性。
任何⼈都不会⽣成与您⽣成的相同的程序集名称,因为⽤⼀个私钥⽣成的程序集的名称与⽤其它私钥⽣成的程序集的名称不相同。
强名称保护程序集的版本沿袭。
强名称可以确保没有⼈能够⽣成您的程序集的后续版本。
⽤户可以确信,他们所加载的程序集的版本出⾃创建该版本的同⼀个发⾏者。
强名称提供可靠的完整性检查。
通过.NET框架安全检查后,即可确信程序集的内容在⽣成后未被更改过。
但请注意,强名称中或强名称本⾝并不暗含某⼀级别的信任,例如由数字签名和⽀持证书提供的信任。
在引⽤具有强名称的程序集时,您应该能够从中受益,例如版本控制和命名保护。
如果此具有强名称的程序集以后引⽤了具有简单名称的程序集,则您将失去使⽤具有强名称的程序集带来的好处,并依旧会产⽣DLL冲突。
因此,具有强名称的程序集只能引⽤其他具有强名称的程序集。
注意:强名称的应⽤程序只能引⽤强名称的dll,不能引⽤未强名称的dll,但是未强名称的dll可以引⽤强名称的dll。
⼆、如何设置强名称上⾯我们讲了什么是强签名,以及强签名的好处,下⾯我们来看看如何给应⽤程序设置强名称。
一、实习背景随着互联网技术的飞速发展,网络安全问题日益突出。
数字签名算法作为一种重要的安全机制,在保障信息安全、防止数据篡改、实现身份认证等方面发挥着至关重要的作用。
为了更好地了解数字签名算法,提高自身在网络安全领域的专业技能,我于近期参加了一次关于数字签名算法的实习活动。
以下是本次实习的详细报告。
二、实习内容1. 数字签名算法概述实习期间,我首先学习了数字签名算法的基本概念、原理和分类。
数字签名是一种利用密码学方法对数字信息进行签名生成和签名验证的技术。
它主要包括非对称加密算法和对称加密算法两大类。
非对称加密算法(公钥加密算法)使用两个密钥:公钥和私钥,公钥是公开的,私钥只有签名者持有。
对称加密算法则使用同一个密钥进行加密和解密。
2. 常见数字签名算法实习过程中,我重点学习了以下几种常见的数字签名算法:(1)RSA数字签名算法:RSA是目前计算机密码学中最经典算法,也是目前为止使用最广泛的数字签名算法。
RSA数字签名算法的密钥实现与RSA的加密算法是一样的,算法的名称都叫RSA。
密钥的产生和转换都是一样的,包括在售的所有SSL数字证书、代码签名证书、文档签名以及邮件签名大多都采用RSA算法进行加密。
(2)DSA数字签名算法:DSA(数字签名算法)是一种基于椭圆曲线的数字签名算法,它提供了一种基于身份的密码体制,即公钥与用户的身份信息即标识相关,从而比传统意义上的公钥密码体制有许多优点。
(3)ECDSA数字签名算法:ECDSA(椭圆曲线数字签名算法)是一种基于椭圆曲线的数字签名算法,它是DSA算法的改进版,具有更高的安全性和效率。
3. 数字签名算法在实际应用中的案例分析实习期间,我还学习了数字签名算法在实际应用中的案例分析,主要包括以下几个方面:(1)电子政务:数字签名算法在电子政务领域得到了广泛应用,如电子公文、电子合同、电子证书等。
(2)电子商务:数字签名算法在电子商务领域发挥着重要作用,如在线支付、电子发票、商品溯源等。
实习报告 .net实习报告2篇实习报告 .net实习报告。
尊敬的领导:
我是一名计算机专业的大学生,在过去的一个月里,我有幸在贵公司进行了为期四周的.NET实习。
通过这次实习,我收获颇丰,深刻体会到了.NET技术在实际项目中的应用和重要性。
在实习期间,我主要参与了公司正在进行的一个.NET项目的开发工作。
在项目中,我学习了C#编程语言的基础知识,并通过实际操作掌握了框架的运用。
在与项目组成员的合作中,我学会了使用Visual Studio等开发工具,熟悉了团队协作的流程和规范。
同时,我也在项目中负责了一些小模块的开发和测试工作,通过这些实际操作,我对.NET技术有了更深入的理解和掌握。
在实习期间,我还有幸参加了公司组织的一些培训和讲座,对.NET技术的发展趋势和应用场景有了更清晰的认识。
同时,我也和一些资深的.NET工程师进行了交流和学习,他们的经验和见解让我受益匪浅。
通过这次实习,我不仅学到了很多专业知识,还提升了自己的实际操作能力和团队协作能力。
在未来的学习和工作中,我将继续努力,不断提升自己,为公司的发展贡献自己的力量。
最后,再次感谢公司给予我这次宝贵的实习机会,我会珍惜并利用好这次学习的机会,希望能有机会再次与贵公司合作。
此致。
敬礼。
XXX。
日期:XXXX年XX月XX日。
中接⼝签名与验签常⽤⽅法现在在程序开发中经常会⽤到第三⽅功能或数据,当我们调取第三⽅接⼝时,⾸先要做的就是要按照他们的规则进⾏验签通过后才可去使⽤。
这也是出于安全⽅⾯的考虑,谁都不想⾃⼰的东西在⽹络中“裸奔”,哈哈。
经常⽤的第三⽅如微信⽀付,第三⽅登录,⽀付宝⽀付等当然还有⼀些短信接⼝,⾝份验证接⼝等,⽽我们⾃⼰的程序对外开放时也会经常⽤到如⾃⼰写的Webapi接⼝等。
下⾯就说⼀下常⽤的签名,验签的⽅式。
_appId:应⽤唯⼀标识_appKey:加密key,⽤来校验应⽤的合法化⼀,签名⼯具类public class SignUtils{//编码格式private static string inputCharset = "utf-8";///<summary>///签名字符串///</summary>///<param name="prestr">需要签名的字符串</param>///<param name="key">密钥</param>///<returns>签名结果</returns>public static string Sign(string prestr, string key){StringBuilder sb = new StringBuilder(32);prestr = prestr + key;MD5 md5 = new MD5CryptoServiceProvider();byte[] t = puteHash(Encoding.GetEncoding(inputCharset).GetBytes(prestr));for (int i = 0; i < t.Length; i++){sb.Append(t[i].ToString("x").PadLeft(2, '0'));}return sb.ToString();}///<summary>///验证签名///</summary>///<param name="prestr">需要签名的字符串</param>///<param name="sign">签名结果</param>///<param name="key">密钥</param>///<returns>验证结果</returns>public static bool Verify(string prestr, string sign, string key){string mysign = Sign(prestr, key);if (mysign == sign){return true;}return false;}///<summary>///⽣成请求时的签名///</summary>///<param name="sPara">请求给⽀付宝的参数数组</param>///<param name="key"></param>///<returns>签名结果</returns>public static string BuildSign(Dictionary<string, string> sPara, string key){//把数组所有元素,按照“参数=参数值”的模式⽤“&”字符拼接成字符串string prestr = CreateLinkString(sPara);//把最终的字符串签名,获得签名结果var mysign = Sign(prestr, key);return mysign;}///<summary>///把数组所有元素,按照“参数=参数值”的模式⽤“&”字符拼接成字符串///</summary>///<param name="dicArray">需要拼接的数组</param>///<returns>拼接完成以后的字符串</returns>public static string CreateLinkString(Dictionary<string, string> dicArray){StringBuilder prestr = new StringBuilder();foreach (KeyValuePair<string, string> temp in dicArray){prestr.Append(temp.Key + "=" + temp.Value + "&");}//去掉最後⼀個&字符int nLen = prestr.Length;prestr.Remove(nLen - 1, 1);return prestr.ToString();}///<summary>///把数组所有元素,按照“参数=参数值”的模式⽤“&”字符拼接成字符串,并对参数值做urlencode///</summary>///<param name="dicArray">需要拼接的数组</param>///<param name="code">字符编码</param>///<returns>拼接完成以后的字符串</returns>public static string CreateLinkStringUrlencode(Dictionary<string, string> dicArray, Encoding code){StringBuilder prestr = new StringBuilder();foreach (KeyValuePair<string, string> temp in dicArray){prestr.Append(temp.Key + "=" + HttpUtility.UrlEncode(temp.Value, code) + "&");}//去掉最後⼀個&字符int nLen = prestr.Length;prestr.Remove(nLen - 1, 1);return prestr.ToString();}///<summary>///除去数组中的空值和签名参数并以字母a到z的顺序排序///</summary>///<param name="dicArrayPre">过滤前的参数组</param>///<returns>过滤后的参数组</returns>public static Dictionary<string, string> FilterPara(SortedDictionary<string, string> dicArrayPre){Dictionary<string, string> dicArray = new Dictionary<string, string>();foreach (KeyValuePair<string, string> temp in dicArrayPre){if (temp.Key.ToLower() != "sign" && !string.IsNullOrEmpty(temp.Value)){dicArray.Add(temp.Key, temp.Value);}}return dicArray;}View Code⼀,签名将传递参数放到SortedDictionary中进⾏操作var dic = new SortedDictionary<string, string>();var parameters = context.ApiActionDescriptor.Parameters;foreach (var apiParameterDescriptor in parameters){var value = apiParameterDescriptor.Value;if (value.GetType() != typeof(string) && value.GetType() != typeof(int)&&value.GetType()!=typeof(long)) {var properties = value.GetType().GetProperties();foreach (var propertyInfo in properties){var val = value.GetType().GetProperty()?.GetValue(value);if (val != null){dic.Add(, val.ToString());}}}else{dic.Add(, apiParameterDescriptor.Value.ToString());}}dic.Add("appid", _appId);//计算signvar sortDic = SignUtils.FilterPara(dic);var newsign = SignUtils.BuildSign(sortDic, _appKey);context.RequestMessage.AddUrlQuery("appid", _appId);context.RequestMessage.AddUrlQuery("sign", newsign);View Code⼆,验签Webapi中验签代码protected override void HandleUnauthorizedRequest(HttpActionContext actionContext){//禁⽤ajax请求var request = HttpContext.Current.Request;var headers = request.Headers;if (headers.AllKeys.Contains("X-Requested-With") && headers["X-Requested-With"] == "XMLHttpRequest"){Failed(actionContext, ResultMessage.Error("不⽀持ajax请求"));return;}//获取参数var dic = new SortedDictionary<string, string>();var streamReader = new StreamReader(request.InputStream);var result = streamReader.ReadToEnd();if (!string.IsNullOrWhiteSpace(result)){var value = JsonConvert.DeserializeObject<JObject>(result);foreach (var property in value.Properties()){dic.Add(, value.GetValue().ToString());}}if (request.Form.AllKeys.Length > 0){foreach (var paramKey in request.Form.AllKeys){dic.Add(paramKey, request.Form[paramKey]);}}if (request.QueryString.AllKeys.Length > 0){foreach (var paramKey in request.QueryString.AllKeys){dic.Add(paramKey, request.QueryString[paramKey]);}}////验签if (!CheckSign(actionContext, dic)){//验签失败}}///<summary>///定义HttpResponseMessage///</summary>///<param name="actionContext">HttpActionContext</param>///<param name="result">ResultMessage api结果返回类型</param>private void Failed(HttpActionContext actionContext, ResultMessage result){actionContext.Response = actionContext.Response ?? new HttpResponseMessage();actionContext.Response.Content = new StringContent(JsonConvert.SerializeObject(result), Encoding.UTF8, "application/json"); }///<summary>///验签///</summary>///<returns>成功返回true</returns>private bool CheckSign(HttpActionContext actionContext, SortedDictionary<string, string> dic){var appKey = ConfigHelper.GetConfigString("apiAppKey");//检查appidif (!CheckKey(actionContext, dic, "appid", out var appId)){return false;}/** 此处直接声明了⼀个AppInfo的对象,实际开发中,要根据appId获取对应的appInfo信息,如下:* var appInfo= appInfoService.GetAppInfo(appId);*///var appInfo = _appInfoService.GetAppInfo(appId);//if (appInfo == null)//{// Failed(actionContext, ResultMessage.Error(ResultEnum.AppNotExists));// return false;//}//检查signif (!CheckKey(actionContext, dic, "sign", out var sign)){return false;}dic.Remove("sign");//计算signvar sortDic = SignUtils.FilterPara(dic);//var newsign = SignUtils.BuildSign(sortDic, appInfo.AppKey);var newsign = SignUtils.BuildSign(sortDic, appKey);//zKmxa_vyJHHUfNGoF85hXHSS5mq3tfwEYjyLMxiMCvoif (newsign != sign){Failed(actionContext, ResultMessage.Error(ResultEnum.InvalidSign));return false;}return true;}///<summary>///检查key///</summary>///<returns></returns>private bool CheckKey(HttpActionContext actionContext, SortedDictionary<string, string> dic, string key, out string value) {value = null;if (!dic.ContainsKey(key)){Failed(actionContext, ResultMessage.ErrorFormat(ResultEnum.LossRequiredParams, key));return false;}value = dic[key];if (string.IsNullOrEmpty(value)){Failed(actionContext, ResultMessage.ErrorFormat(ResultEnum.InvalidParams, key));return false;}return true;}View Code。
通过嵌入公钥并使用私钥签名,可以生成强名称(strong name)的程序集。
强名称程序集由4部分进行标识:名称、版本、区域性和公钥。
与之相对的,我们可以把没有嵌入公钥和使用私钥签名的程序集称之为弱名称(weak name)程序集(这个术语是Jffery Richter 创造的)。
强名称程序集与弱名称程序集相比,有以下特点:* 强名称程序集可以保证唯一性。
公/私密钥对是由发行者自行生成的,是唯一的,保证了程序集的标识不会重复。
* 强名称程序集可以防篡改。
强类型程序集使用私钥对自己进行了签名,这样在被加载时可以检查程序集是否被修改。
* 强名称程序集可以实施版本策略。
对于弱名称程序集,引用它的程序不会关心它的版本,而对于强类型的程序集来说,引用它的程序会被绑定到特定版本的程序集上,如果使用新版本的强名称程序集替换旧版本,会导致程序无法运行。
(当然还可以使用配置文件对强名称程序集进行重定向)。
* 强名称程序集可以部署到GAC中。
GAC指全局程序集缓存,这是一个公共目录,放在此处的程序集可以被本机任意一个程序所引用。
弱名称程序集无法部署到此处。
不同版本的相同程序集还可以同时存在于GAC中。
* 强名称程序集只能引用强名称程序集。
弱名称程序集可以引用强名称程序集,也可以引用弱名称程序集,但强名称程序集只能引用强名称程序集。
* 强名称程序集支持并行执行。
并行(side-by-side)执行是指程序同时引用了多个版本的同名程序集,这样在运行时,会有多个版本的同名程序集被加载和同时执行。
通常不建议使用。
下面来研究一下如何生成强名称的程序集。
首先,使用SN.exe创建一个密钥文件:sn.exe -k MyKey.snk生成的文件包含了公钥和私钥的内容。
我们可以查看公钥的内容,私钥是不允许查看的,所以要先将公钥提取出来。
仍然是使用SN.exe:sn -p MyKey.snk MyPublicKey.snksn -tp MyPublicKey.snk前一个命令将密钥文件中的公钥提取出来,放到MyPublicKey.snk 文件中;后一个命令用于显示该文件中的公钥和公钥标记(Public key token),显示的内容可能如下(每个人生成的都不同):Microsoft (R) .NET Framework Strong Name Utility Version 3.5.21022.8Copyright (c) Microsoft Corporation. All rights reserved.Public key is 0024000004800000940000000602000000240000525341310004000001000100757c8b7 854ffcb4763250746c094e45db0c715214415fb01bd178f3374224c1292dbbc9dddfb6af7de17668 884641a39fbea9d0bee001c093b228400aa39c0db5724fc11c221bd2c7442a30ef26c076b1bb0f 559ce7955572b4174125494a593c199d968019323483e72d5bdb93d96af14ccfeb0c5d4af6ea19 1d226e6812db5Public key token is 337642649f453c2c公钥标记是公钥的64位散列值,用于简化对公钥的引用。
⽤强名称程序集(转)为Microsoft .NET框架创建应⽤程序时,你获得的最⼤的⼀个承诺就是能避免所谓的DLL地狱(/2100-1012-991466.html)。
它是指当⼀个组件更新后,可能会中断依赖于它的其他应⽤程序。
然⽽,为了理解这个承诺,开发者需要熟悉“强名称”(Strong Names)的概念与实现。
本⽂将引导你理解强名称在托管代码中的应⽤。
为什么要使⽤强名称在讨论强名称的好处之前,先来看看它的定义。
强名称由⽤于标识⼀个程序集的信息构成,其中包括程序集的⽂本名称、分为4部分的版本号、区域性信息(如果有的话)、⼀个公钥以及⼀个数字签名。
这些信息存储在程序集的清单(manifest)中。
清单包含了程序集的元数据,并嵌⼊程序集的某个⽂件中。
--------------------------------------------------------------------------------注意⼤多数程序集(⽐如使⽤Visual Studio .NET创建的那些)都是单⽂件程序集,也就是只有⼀个.exe或者.dll⽂件。
在这种情况下,清单直接嵌⼊单⽂件程序集中。
但是,你可⽤“程序集⽣成⼯具”(Al.exe)来创建多⽂件程序集。
--------------------------------------------------------------------------------在程序集中包括⼀个强名称后,公共语⾔运⾏库(CLR)可保证具有相同强名称的两个程序集在任何⽅⾯都是完全⼀致的。
换⾔之,强名称为CLR提供了⼀个程序集的惟⼀性标识。
除此之外,添加⼀个强名称还可确保⼆进制完整性,因为CLR可在程序集加载时执⾏验证,判断它⾃从编译以来是否被篡改过。
在两种主要的情况下,开发者应为⼀个程序集包括强名称:共享程序集。
通过包括强名称,程序集在安装到“全局程序集缓存”(GAC)之后,就由同⼀台机器上运⾏的多个应⽤程序共享。
NET实习总结报告第一点:NET实习经历回顾在过去的几个月里,我有幸参加了一次基于.NET技术栈的实习项目。
这次实习对我来说是一次宝贵的经历,让我对.NET开发有了更深入的了解和实践。
在实习期间,我参与了一个电子商务平台的开发,负责设计和实现部分功能模块。
这个项目采用敏捷开发模式,让我体验到了实际工作中开发流程和团队协作的重要性。
在技术层面,我深入学习了.NET Core框架,掌握了C#编程语言,熟悉了Entity Framework Core作为数据访问层的技术。
同时,我还学会了使用 Core构建Web应用程序,并使用了诸如Redis、RabbitMQ等中间件来优化系统性能。
除了技术学习,我还积极参与了团队的日常开发工作,与团队成员沟通交流,分享技术心得。
在实际开发过程中,我遇到了很多问题,但通过查阅资料、请教同事和不断尝试,我逐渐找到了解决问题的方法。
这些经验让我在面对未知问题时更加从容和自信。
实习期间,我还参加了公司举办的多次技术培训和分享会,拓宽了自己的技术视野。
在与同事的交流中,我学到了很多关于软件工程、项目管理和团队协作的经验,这些都是课堂上学不到的宝贵财富。
第二点:实习收获与反思通过这次实习,我收获了很多在课堂上学不到的东西。
首先,我认识到了实际工作与学校学习的差异。
在实习项目中,我需要独立解决问题,而不是依赖老师的指导。
这让我明白了自主学习和解决问题的能力在工作中是多么重要。
其次,我学会了如何在团队中协作。
在实习过程中,我与团队成员共同承担责任,共同解决问题。
这让我认识到,团队协作是软件开发中不可或缺的一环。
此外,我还认识到了自己的不足。
在实习过程中,我发现自己在某些方面的技术水平和经验还有待提高。
这让我更加坚定了继续学习的信念,努力提升自己的技术能力。
在反思这次实习经历时,我认为自己在以下几个方面还有待提高:1.沟通协作能力:在实际工作中,沟通协作至关重要。
我需要学会如何更好地与团队成员沟通,提高工作效率。
计算机与信息工程学院《.NET程序设计》实训报告
课程名称:电子商务
专业、班级:2012电子商务班
姓名:
学号:
日期:2015年11 月20日
BBS系统设计与开发
一、需求分析简介
通常的BBS系统的功能要素包括用户注册,用户登录,帖子查询,发帖,回帖和管理员维护等。
根据这些要素可以设计出小型BBS系统的功能模块如下。
(1)用户注册:用户名不允许重名。
(2)用户登录:允许注册用户和访客登录。
(3)查询主贴:分页显示主贴的标题等信息。
(4)详细信息:查询主贴的详细信息及其全部回复信息。
(5)发表新主贴:可以输入新帖并插入数据库中。
(6)回复:对某个主贴进行回复。
(7)管理员登录:只允许管理员登录。
(8)删除主贴及其全部回复:可以在主贴列表中选择并删除某个主
贴。
二、概念结构设计(ER图)(用Visio画图)
三、功能设计(功能图)
四、数据库设计
五、各文件夹及文件功能描述
主帖表
管理员信息表(adminUser)
回帖表
六、主要程序界面及源代码
七、测试。
.net程序集强名称签名实践强名称是由程序集的标识加上公钥和数字签名组成的。
其中,程序集的标识包括简单文本名称、版本号和区域性信息(如果提供的话)。
强名称是使用相应的私钥,通过程序集文件(包含程序集清单的文件,并因而也包含构成该程序集的所有文件的名称和散列)生成的。
Microsoft® Visual Studio® .NET 和在 .NET Framework SDK 中提供的其他开发工具能够将强名称分配给一个程序集。
强名称相同的程序集应该是相同的。
通过签发具有强名称的程序集,您可以确保名称的全局唯一性。
强名称还特别满足以下要求:1)强名称依赖于唯一的密钥对来确保名称的唯一性。
任何人都不会生成与您生成的相同的程序集名称,因为用一个私钥生成的程序集的名称与用其他私钥生成的程序集的名称不相同。
2)强名称保护程序集的版本沿袭。
强名称可以确保没有人能够生成您的程序集的后续版本。
用户可以确信,他们所加载的程序集的版本出自创建该版本(应用程序是用该版本生成的)的同一个发行者。
强名称提供可靠的完整性检查。
通过 .NET Framework 安全检查后,即可确信程序集的内容在生成后未被更改过。
但请注意,强名称中或强名称本身并不暗含信任级别,例如由数字签名和支持证书提供的信任。
虽然强名称是.NET加密领域的元老,也是微软推荐的应用程序保护机制,但是由于托管程序可以被反汇编成IL代码,更改或者去除强名称也就成了可能。
强名称的保护强度也因此大大减弱。
一、使用强名称保护代码完整性当我们从互联网上下载一个程序集供本地调用的时候,如何保证这个程序集是未经第三方恶意篡改过的呢?如果两个程序集的名称、大小、版本号都相同是不是就意味着这两个程序集文件就相同了呢?在.NET平台下区分程序集采用的方法和Win32一样,使用名称,但是名称有强弱之分。
弱名称包含版本号、程序集名称和文化。
强名称在弱名称的基础上添加了数字签名。
强名称的作用主要有三个:一是区分不同的程序集;二是确保代码没有被篡改过;三是在.NET中,只有强名称签名的程序集才能放到全局程序集缓存中。
使用强名称来包含程序集我们首先要生成用于非对称加密的密钥对,这对密钥将用于程序集的签署和验证。
签署和验证的流程如图1所示。
图1 签署(上)与验证(下)强名称流程如图1所示,在进行强名称签名的时候我们首先对程序集(不包括DOS头和PE头)进行Hash运算,得到文件的散列值,然后使用私钥对散列值进行加密,得到密文。
然后将公钥、公钥标识(对公钥进行SHA-1散列运算后得到的密文的最后8个字节)和密文三个信息保存在程序集中。
在加载该程序集时,首先对该程序集进行Hash运算得到一个Hash值(我们称之为“新Hash值”),然后从程序集中提取公钥对密文解密得到原始的Hash值,如果两个Hash值相同,即通过验证。
对程序集签名有正常签名和延迟签名两种方式。
延迟签名是在我们开发人员只具有对公钥的访问权限而没有对私钥的访问权限时使用的。
这是我们可以先将程序集编译并预留签名空间。
此时的程序集无法正常运行和调试。
1、在SDK中创建强名称签名的程序集对程序集进行强名称签名,我们要首先准备好密钥。
可以使用Visual Studio SDK中提供的强名称工具(Sn.exe)可以生成密钥对。
我们使用如图2的命令生成一个新的密钥对并保存到本地文件test.snk中。
图2 生成密钥文件接下来我们新建一个控制台测试项目StrongName,StrongName项目主要代码using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Reflection;namespace StrongName{class Program{static void Main(string[] args){string aa = "";Assembly ass = Assembly.GetExecutingAssembly();Console.WriteLine(ass.FullName.ToString());byte[] pKey = ass.GetName().GetPublicKey();byte[] pKeyToken = ass.GetName().GetPublicKeyToken();string pKeyString = GetString(pKey);string pKeyTokenString = GetString(pKeyToken);Console.WriteLine("公钥是:{0}",pKeyString);Console.WriteLine("公钥标识是{0}", pKeyTokenString);Console.Read();}private static string GetString(byte[] bytes){StringBuilder sb = new StringBuilder();foreach (byte b in bytes){sb.Append(string.Format("{0:x}",b));}return sb.ToString();}}}代码很简单,使用反射来列举当前程序集的名称和使用的公钥及公钥标识。
在没有对程序集进行强名称签名时我们运行程序得到如图3的结果。
图3 没有对程序集进行强名称签名时代码的运行结果下面我们在命令行对C#编译器(csc.exe)执行如图所示的命令。
图4对程序集应用强名称现在我们再来执行刚才生成的Program.exe,看看结果如何,如图5所示。
图5对程序集进行强名称签名之后代码的运行结果从图5我们可已看出,执行强名称签名之后我们成功的输出公钥和公钥标识。
为了使编译器能自动为代码进行强名称签名我们可以为代码添加特性指明强名称签名需要的密钥文件。
添加特性之后的代码示下所示。
使用特性进行强名称签名using System;using System.Reflection;[assembly:AssemblyKeyFileAttribute("TestKey.snk")]代码使用 AssemblyKeyFileAttribute 指定包含密钥对的文件的名称。
当我们需要对程序集进行延迟签名的时候,我们需要对 AssemblyDelaySignAttribute 特性和AssemblyKeyFileAttribute 联合使用,代码如下。
对程序集延迟签名的特性声明using System;using System.Reflection;[assembly:AssemblyKeyFileAttribute("myKey.snk")][assembly:AssemblyDelaySignAttribute(true)]在代码中,当我们需要对程序集延迟签名的时候,我们要指定包含公钥的文件并设定As semblyDelaySignAttribute特性值为true。
2、在VS中创建强名称签名的程序集在SDK中进行强名称签名未免麻烦了一些,下面我们以VS2010为例,讲解如何在Visua l Studio中进行强名称签名的操作。
我们打开项目的属性,切换到签名页,如图6所示。
图6 项目的签名页从图6中我可以看出,项目签名属性页中包含了三个大的配置项,第一个是为ClickOnc e清单签名,第二个是为程序集签名,第三个是延迟签名。
什么是 ClickOnce 应用程序?ClickOnce 应用程序是使用 ClickOnce 技术发布的任何 Windows Presentation Found ation (.xbap)、Windows 窗体 (.exe)、控制台应用程序 (.exe) 或 Office 解决方案 (.d ll)。
可以采用三种不同的方式发布 ClickOnce 应用程序:从网页发布、从网络文件共享发布或者从媒体(如 CD-ROM)发布。
ClickOnce 应用程序可以安装在最终用户的计算机上并在本地运行(即使该计算机处于脱机状态),或者也可以在仅限联机模式下运行,而不用在最终用户的计算机上永久性安装任何内容。
有关更多信息,请参见选择 ClickOnce 部署策略。
ClickOnce 应用程序可以自行更新;这些应用程序可以在较新版本可用时检查是否存在较新版本,并自动替换所有更新后的文件。
开发人员可以指定更新行为;网络管理员也可以控制更新策略,如将更新标记为强制性的。
最终用户或管理员还可以对更新进行回滚,使应用程序恢复到早期的版本。
有关更多信息,请参见选择 ClickOnce 更新策略。
因为 ClickOnce 应用程序是独立的,所以安装或运行 ClickOnce 应用程序不会破坏现有的应用程序。
ClickOnce 应用程序是自包含的;每个 ClickOnce 应用程序都会安装到一个安全的、基于每个用户和每个应用程序的缓存中,并从中运行。
ClickOnce 应用程序在Internet 或 Intranet 安全区域中运行。
如果有必要,应用程序可以请求提升的安全权限。
有关更多信息,请参见保护 ClickOnce 应用程序。
程序集签名(也称为强名称签名)赋予应用程序或组件一个唯一标识,其他软件可用该标识来显式标识和引用该应用程序或组件。
强名称由程序集的简单文本名、版本号、区域性信息(如果提供)以及公钥/私钥对组成。
为了使用ClickOnce部署发布应用程序,应用程序和部署清单必须使用公钥/私钥对进行强命名并使用Authenticod 技术进行签名。
可以使用Windows证书存储区的证书或密钥文件为清单签名。
也可以创建新的测试证书。
为程序集签名的选项中,我们可以选择密钥文件或者生成新的密钥文件来对程序集进行签名。
如果勾选了仅延迟签名,那么将对程序集进行延迟签名。
如图7,在创建了ClickOnce签名和程序集签名之后,项目自动添加了两个密钥文件St rongName_TemporaryKey.pfx和test.pfx。
图7 创建ClickOnce签名和程序集签名强名称签名的程序集如果被篡改,那么CLR在加载该程序集进行完整性验证的时候就会失败。
我们现在使用文本编辑工具打开StrongName.exe,在保证不破坏PE文件格式的前提下对其进行简单的修改,这里我只把程序中定义的变量aa替换成bb,如图8所示。
图8 修改强名称签名的程序集修改之后,我们再次运行StrongName.exe,看到程序报出的异常为强名称验证失败,入图9所示。