先声明该文的实用性不强, 要产生一对密钥可以有更简单的方法。该文简单解释了.snk文件的格式,并给出了从中提取密钥的C#代码。

.snk文件(Strong Name Key)也可以叫签名文件,它一般用来给DotNet程序集进行强命名。它的好处是非常容易产生,也非常容易管理。我们可以在Visual Studio的项目设置中新建一个签名文件,也可以用sn.exe -k key.snk命令行来产生一个。

.snk可以只包含一个公钥,也可以同时包含公钥和私钥。其中私钥可以用来对程序集进行签名,而公钥则可以用来验证一个签名。由于该密钥实际上就是一个1024位的RSA密钥,我们也可以用.snk文件来进行RSA应用。比如进行非对称加密,进行Xml数字签名和验证等等。

目前就我知道的,snk格式没有正式公开。不过包含公钥和私钥的.snk实际上就是一个PRIVATEKEYBLOB结构。该结构的定义见:

http://msdn.microsoft.com/en-us/library/aa387401(v=vs.85).aspx

该结构由一个BLOBHEADER头结构,一个RSAPUBKEY结构,以及一些RSA钥匙数据组成。其中BLOBHEADER.bType为PRIVATEKEYBLOB(0x7),指明该文件包含了私钥;而BLOBHEADER.aiKeyAlg固定为CALG_RSA_SIGN,指明该钥匙用来签名;RSAPUBKEY.bitlen指定了RSA密钥的长度,该长度将影响那一些钥匙数据的长度,这里我们把它固定为1024位。

下列C#代码示例如何将带私钥的签名文件读入到的结构中,并导出一个RSA钥匙:

 
[StructLayout( LayoutKind.Sequential, Pack=1)]
struct BLOBHEADER
{
    public byte bType;      //PRIVATEKEYBLOB = 0x7
    public byte bVersion;   //Digital Signature Standard=3; CUR_BLOB_VERSION=2
    public short reserved;  //
    public uint aiKeyAlg;   //CALG_RSA_KEYX=0xa400; CALG_RSA_SIGN=0x2400
} 
 
[StructLayout( LayoutKind.Sequential, Pack=1)]
struct RSAPUBKEY 
{
    public int magic;       //0x32415352 ("RSA2") for public/private key; ("RSA1") for public key only
    public int bitlen;      //Number of bits in the modulus. A multiple of eight.
    public int pubexp;      //The public exponent
}
 
[StructLayout( LayoutKind.Sequential, Pack=1)]
struct PRIVATEKEYBLOB 
{
    public BLOBHEADER blobheader;
    public RSAPUBKEY rsapubkey;
    [MarshalAs( UnmanagedType.ByValArray, SizeConst=128)]
    public byte[] modulus;          //[rsapubkey.bitlen/8];  as Modulus
    [MarshalAs( UnmanagedType.ByValArray, SizeConst=64)]
    public byte[] prime1;           //[rsapubkey.bitlen/16]; as P
    [MarshalAs( UnmanagedType.ByValArray, SizeConst=64)]
    public byte[] prime2;           //[rsapubkey.bitlen/16]; as Q
    [MarshalAs( UnmanagedType.ByValArray, SizeConst=64)]
    public byte[] exponent1;        //[rsapubkey.bitlen/16]; as D mod (P - 1)".
    [MarshalAs( UnmanagedType.ByValArray, SizeConst=64)]
    public byte[] exponent2;        //[rsapubkey.bitlen/16]; as D mod (Q - 1)".
    [MarshalAs( UnmanagedType.ByValArray, SizeConst=64)]
    public byte[] coefficient;      //[rsapubkey.bitlen/16]; as InverseQ
    [MarshalAs( UnmanagedType.ByValArray, SizeConst=128)]
    public byte[] privateExponent;  //[rsapubkey.bitlen/8];  as D
 
    public RSAParameters GetRSAKey()
    {
        RSAParameters key = new RSAParameters()
        {
            Modulus = this.modulus,
            P = this.prime1,
            Q = this.prime2,
            DP = this.exponent1,
            DQ = this.exponent2,
            InverseQ = this.coefficient,
            D = this.privateExponent,
            Exponent = BitConverter.GetBytes(this.rsapubkey.pubexp),
        };
        Array[] arrays = {key.Modulus, key.P, key.Q, key.DP, key.DQ, key.InverseQ, key.D, key.Exponent};
        foreach(Array a in arrays)
        {
            Array.Reverse(a);
        }
        return key;
    }
 
    public static RSAParameters LoadFromSNK(string filename)
    {
        byte[] raw = File.ReadAllBytes(filename);
        if (raw.Length != Marshal.SizeOf(typeof(PRIVATEKEYBLOB)))
        {
            throw new InvalidOperationException("not a valid snk file with public/private key");
        }
        GCHandle gc = GCHandle.Alloc(raw, GCHandleType.Pinned);
        PRIVATEKEYBLOB b = (PRIVATEKEYBLOB)Marshal.PtrToStructure(gc.AddrOfPinnedObject(), typeof(PRIVATEKEYBLOB));
        gc.Free();
        return b.GetRSAKey();
    }
}
 

只包含公钥的.snk文件可以通过sn.exe -p key.snk public.snk来产生。这种只包含公钥的.snk文件格式则是PUBLICKEYBLOB的基础上,加上一些额外包装。PUBLICKEYBLOB结构的定义见:

http://msdn.microsoft.com/en-us/library/aa387459(v=vs.85).aspx

额外包装为4个字节的签名算法;4个字节的散列算法;以及4个字节的钥匙长度。这额外的12字节,加上PUBLICKEYBLOB的148字节,总好是(只包含公钥的).snk的总长度,160字节。

下列为代码表示:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct PUBLICKEYBLOB
{
    //.Net wrapper
    public int signatureAlg;             //CALG_RSA_SIGN=0x2400
    public int hashAlg;                  //CALG_SHA1=0x8004
    public int blobLength;               //148
 
    public BLOBHEADER blobheader;
    public RSAPUBKEY rsapubkey;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
    public byte[] modulus;               //[rsapubkey.bitlen/8];  as Modulus
 
    public RSAParameters GetRSAKey()
    {
        RSAParameters key = new RSAParameters()
        {
            Modulus = this.modulus,
            Exponent = BitConverter.GetBytes(this.rsapubkey.pubexp),
        };
        Array[] arrays = { key.Modulus, key.Exponent };
        foreach (Array a in arrays)
        {
            Array.Reverse(a);
        }
        return key;
    }
}

导出公钥还有其他的办法。一个办法是将.snk导入到当前系统的钥匙容器中,既sn.exe -i key.snk mykeycontainer。然后再用RSACrytoServiceProvider.ExportParameters来导出公钥:

CspParameters cp = new CspParameters(1);
cp.KeyContainerName = "mykeycontainer";
cp.KeyNumber = (int)KeyNumber.Signature;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
RSAParameters publicKey = rsa.ExportParameters(false);

不过这种方法对私钥无效。虽然sn.exe可以将钥匙导入到容器的KeyNumber.Signature上,但该钥匙被标志为不可导出。也就是说调用rsa.ExportParameters(true)将抛出异常。

从.snk文件导出密钥的更多相关文章

  1. C#+OpenGL+FreeType显示3D文字(1) - 从TTF文件导出字形贴图

    C#+OpenGL+FreeType显示3D文字(1) - 从TTF文件导出字形贴图 +BIT祝威+悄悄在此留下版了个权的信息说: 最近需要用OpenGL绘制文字,这是个很费时费力的事.一般的思路就是 ...

  2. loadrunner实现excel文件导出操作

    项目中需要对“商品信息”进行查询及导出,但是loadrunner并不能录制到“保存”这一操作. 项目介绍:flex+Http协议: 不能录制的原因: 在我们点击了“导出”按钮后,服务端已经生成一份我们 ...

  3. C#进行Visio二次开发之文件导出及另存Web页面

    在我前面很多关于Visio的开发过程中,介绍了各种Visio的C#开发应用场景,包括对Visio的文档.模具文档.形状.属性数据.各种事件等相关的基础处理,以及Visio本身的整体项目应用,虽然时间过 ...

  4. 如何利用.snk文件生成DLL文件中的Publickeytoken

    1.在该路径下C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin查找是否有sn.exe. 没有的话,从网上下载,注意需要的版本. 2.打开c ...

  5. Ado.Net小练习01(数据库文件导出,导入)

    数据库文件导出主要程序: <span style="font-family: Arial, Helvetica, sans-serif;"><span style ...

  6. .Net 程序集 签名工具sn.exe 密钥对SNK文件 最基本的用法

    阐述签名工具这个概念之前,我先说说它不是什么: 1.它不是用于给程序集加密的工具,它与阻止Reflector或ILSpy对程序集进行反编译一毛钱关系都没有. 2.它很讨厌人们把它和加密联系在一起. 我 ...

  7. JAVA实用案例之文件导出(JasperReport踩坑实录)

    写在最前面 想想来新公司也快五个月了,恍惚一瞬间. 翻了翻博客,因为太忙,也有将近五个多月没认真总结过了. 正好趁着今天老婆出门团建的机会,记录下最近这段时间遇到的大坑-JasperReport. 六 ...

  8. 文件导出也可以这么写【js+blob】

    文件导出在软件开发中是个比较常用的功能,基本原理也很简单: 浏览器向后台发送一个Get请求 后台处理程序接收到请求后,经过处理,返回二进制文件流 浏览器接收到二进制文件流后提示下载文件 调用的js方法 ...

  9. 转载:.Net 程序集 签名工具sn.exe 密钥对SNK文件 最基本的用法

    .Net 程序集 签名工具sn.exe 密钥对SNK文件 最基本的用法 阐述签名工具这个概念之前,我先说说它不是什么: 1.它不是用于给程序集加密的工具,它与阻止Reflector或ILSpy对程序集 ...

随机推荐

  1. RESTful 个人理解总结【转】

    转自:http://www.cnblogs.com/wang-yaz/p/9237981.html 一.什么是RESTful 面向资源 简单的说:RESTful是一种架构的规范与约束.原则,符合这种规 ...

  2. python enumerate用法总结【转】

    enumerate()说明 enumerate()是python的内置函数 enumerate在字典上是枚举.列举的意思 对于一个可迭代的(iterable)/可遍历的对象(如列表.字符串),enum ...

  3. Python学习五|集合、布尔、字符串的一些特点

    #集合本身就像无值的字典 list1 = set([1,2,3,4]) list2 = {1,2,3,4} print('list1 == list2?:',list1==list2)#list1 = ...

  4. Qt 程序等待多长时间执行Sleep

    #include <QTime> void MainWindow::Sleep(unsigned int msec) { QTime reachTime=QTime::currentTim ...

  5. jquery-事件之页面框架加载后自动执行

    jQuery事件之页面框架加载后自动执行 1)概述 HTML执行是按自上而下编译,而<script>一般写在body结束之前.如果在HTML加载的过程中卡住, 比如加载图片等,没有显示出来 ...

  6. SNMP中MIB2所有主要节点

    系统组:system组包含以下对象集(.1.3.6.1.2.1.1): 对象名:sysDescr(1) OID:system.1 对象类型:DisplayString[255] 访问模式:只读 描述: ...

  7. POJ 1948 Triangular Pastures

    题意: 把很多单独的线段重新组合成一个三角形,使得三角形面积最大(所有的线段都必须用上). 思路: 三角形的任意一条边的边长不能超过周长的一半,只需要用dp枚举两条边j,k,剩下的一条边长为tot  ...

  8. 使用Golang编写优化算法 (1)

    动手写点东西是学习新知识很重要的一个阶段.之前用 Python 和 JavaScript 实现优化算法,现在用 Golang 来实现.语法上略有不爽,某些C语言的思维又回来了. - Golang 用 ...

  9. Ocelot + IdentityServer4 构建 GateWay

    上一篇已经构建好了例子,接下来将IdentityServer4添加到Ocelot中去实现 配置一个客户端配置,可以构建一个简单的客户端信息,这里我用的混合模式,配置比较多,对于客户端模式而言实际很多都 ...

  10. 【LOJ】#2080. 「JSOI2016」病毒感染

    题解 那个限制表示一回头要治完前面的所有病人 我们处理一个g[i][j]表示治疗i到j的病人至少会死多少病人 \(g[i][j] = g[i + 1][j] + sum[i + 1,j] + min( ...