(答案是完全重写的,一些不那么有趣的想法和片段可以在

previous revisions中找到)

对SignHash的调用(btHash,CryptoConfig.MapNameToOID(“SHA256”))执行PKCS#1 v1.5签名(RSASSA-PKCS1-v1_5),例如:

byte[] btHash = new byte[] { 0x57,0x91,0x16,0xB6,0x3E,0x06,0x58,0x83,0x24,0x8C,0x07,0xDA,0x6A,0x03,0x4D,0x23,0x37,0x0B,0x32,0x1C,0xA0,0x80,0x08,0x1F,0x42,0x81,0x8E,0x54,0x3A,0xC6 };

X509Certificate2 cert = new X509Certificate2("dummy.p12","1234",X509KeyStorageFlags.Exportable);

using (RSACryptoServiceProvider key = new RSACryptoServiceProvider())

{

key.FromXmlString(cert.PrivateKey.ToXmlString(true));

byte[] ret = key.SignHash(btHash,CryptoConfig.MapNameToOID("SHA256"));

}

提供签名:

0A5003E549C4E4310F720076A5A4D785B165C4FE352110F6CA9877EB9F364D0C40B0197110304D6F92E8BD40DFD38DB91F356601CDD2CD34129BC54492C2D7F371D431150288A95C21E47533F01A9FA4977439FF9594C703380BEDF49A47A7B060ECAC26AEB53B8732D93E18FAD3B2D5889B3311C1B0D4F9F6B318169BDEB143D771DEFB56BAFE49B2B59F172757D4273EF369AFCB32490EC954E17599BD66D4E3BDB345B860748DB0C3B5A272ECFA546E65F2D4C87870CC62D91680AB71DB52DE618C006356258A941E8F36A5DCC7A06BA6DACAC3DC35F482B168107B4D7DA6C19A56FEDC247232DD7210CA9DB7273AA9AE6A90A8A4DFEB64BA0FBC830AB922

其中包含PKCS#1 v1.5填充DigestInfo和哈希(当使用公钥解密时):

0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003031300D060960864801650304020105000420579116B63E065883248C0716DA6A034D23370B321CA080081F4203818E543AC6

由于您只有哈希(而不是数据)要签名,您需要在java中使用NONEwithRSA algorithm(它应该执行PKCS#1 v1.5填充输入数据的签名,而不需要任何哈希值),并生成正确的输入DigestInfo与手动散列OID.像这样(在Apache Commons Lang的帮助下)::

byte[] btHash = new byte[] { ....the same.... };

KeyStore keystore = KeyStore.getInstance("PKCS12");

keystore.load(new FileInputStream("dummy.p12"),"1234".tocharArray());

PrivateKey privKey = (PrivateKey)keystore.getKey("Dummy","1234".tocharArray());

byte[] asn=ArrayUtils.addAll(new byte[] { (byte)0x30,(byte)0x31,(byte)0x30,(byte)0x0d,(byte)0x06,(byte)0x09,(byte)0x60,(byte)0x86,(byte)0x48,(byte)0x01,(byte)0x65,(byte)0x03,(byte)0x04,(byte)0x02,(byte)0x05,(byte)0x00,(byte)0x20},btHash);

Signature signature = Signature.getInstance("NONEwithRSA");

signature.initSign(privKey);

signature.update(asn);

byte[] ret = signature.sign();

它给出与C#代码相同的签名(使用默认的SunJCE / SunRsaSign提供程序).

SunMSCAPI提供商supports the NONEWithRSA algorithm具有限制.引用sun.security.mscapi.RSASignature javadoc:

NOTE: NONEwithRSA must be supplied with a pre-computed message digest.

Only the following digest algorithms are supported: MD5,SHA-1,

SHA-256,SHA-384,SHA-512 and a special-purpose digest algorithm which

is a concatenation of SHA-1 and MD5 digests.

其中一见钟情可能适用于这种情况.不幸:

Signature mscapiSignatureNoneWithRSA = Signature.getInstance("NONEwithRSA","SunMSCAPI");

mscapiSignatureNoneWithRSA.initSign(mscapiPrivKey);

mscapiSignatureNoneWithRSA.update(btHash);

byte[] mscapiSignatureNoneWithRSA_btHash = mscapiSignatureNoneWithRSA.sign();

提供不同的签名:

CE26A9F84A85037856D8F910141CE7F68D6CAAB416E5C2D48ACD9677BBACCB46B41500452A79018A22AB1CA866DD878A76B040A343C1BABCDB683AFA8CE1A6CCCA48E3120521E8A7E4F8B62B453565E6A6DC08273084C0748C337724A84929630DC79E2EB1F45F5EEBA2148EC0CA5178F2A232A2AE8A5D22BB06C508659051CD1F5A36951B60F6322C5AEB5D4461FABE4D84E28766501A1583EC2A5D8553C163EC8DB9E80EF972233516BEC50AAC38E54C8B5E3B3DEAE90F37A1D230CD976ABEEE97A4601461E842F0F548DA7A74645AAB42586044B084E6A9F3EFE409EE12D98EB0B16CDC2C0AB75BF5DC9B52EBB7E3303C53A2B1BDF14000B99112B1871A6A

其中只包含PKCS#1 v1.5填充的哈希值(没有ASN.1 DigestInfo序列/在这种情况下是错误的):

0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00579116B63E065883248C0716DA6A034D23370B321CA080081F4203818E543AC6

尝试从SunJCE示例中签署DigestInfo提供了一个例外:

java.security.SignatureException: Message digest is too long

(Here和here是这种行为的原因.)

使用RSA私钥加密生成签名的另一种方法,它与SunJCE提供者(使用与上述相同的asn变量)提供与C#代码相同的签名:

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");

cipher.init(Cipher.ENCRYPT_MODE,privKey);

byte[] ret = cipher.doFinal(asn);

不适用于SunMSCAPI提供程序:

cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding","SunMSCAPI");

cipher.init(Cipher.ENCRYPT_MODE,mscapiPrivKey);

byte[] ret = cipher.doFinal(asn1);

如它所示:

4A540DFAD44EBDAE89BF5DD52121DA831E7C394E0586DC9EAEF949C466E649979E19DF81A44801EBD80B8946605B4EFCED53011A844A3A4E023136F0CDEAA57EAAB1EA1FA75400B3B2D5FAB3955BEB13A178AC03DED6AACA0571412B74BCE30E772082A368B58E94D8E20D8F2A116BA5B3881824A014281E9F04BD687C087ACF7164CAF7C74274BA356A671ADA2BB4142504DB2883AFEDA563C6E590BC962725D6697402AB24391409F50D7D16B8BF64A1C0224C379EF9C7B8E493BE889A70674C3AEEC524366DBF9DE36FEE01F186FC00DE2F06096C46CC873D37E194CB217FBFCCF450C1F96C804022E25E1589DF67247927AAD59C66294B027DD5EE991D46

使用公共密钥进行解密是一个废话:

3A9E0F985D1CF2CFDB45F201A68EF0F241ADBAED2D945FD36451CB4BE77D9B30D977004F95E6EDC208805E62870CD19D87C5E7F4E4C1AC2546F7F9C410299C9D203C47C2B547BAA55DA05C44DACB7E07C3F0DB99AE291E48A67EE089F8DA34EB1AABE352A7F94B082CFB167C0FE90761B79FCE238A0F3D0D917CA51220EEA9A43877703FC06CDC1F13A77CA9904E3660F7AD84DE0C34C877B737C20B1A117E60D69E6766054A30B95E6E88CF2C11AEE5CE30F2DD780C0334BE085302E73E0E5BB096893B7155E7A48CA16DD5EA9FC6F63090F7223E7FBAAA133BDFDA7251F412E395F4D8A462569BC5DCC34C2DF7D996BB3278C3F6B0E1EE9E729925937C8BAE

但是(更有趣的是)当使用私钥解密时,包含一个有效的PKCS#1 v1.5填充加密明文:

000211F7946FAD6BDB18830F8DD1238FD7EFCCFF041D55B88FBABDAAA6B06A5E9FD7556EB33678D9954D26E07B2FCE6D7304386DBDFC352C9932E2BA1794A3A0E0F6D78AA656DEB36CC483171A77ABF34408F4BF60661ECA79852B8E39C1A710976208FFBF6BE0DFB566149E6C5838762316F394B70BDF6D494F8C43C42CB6E527292DEF9204712CB24AC82C572BBC0E70A298D5FB050A27B54AFFA1332EEF37A14E65D379968BCE717BEC37C67A180DE943AAF2FE83560D33BC588E11B85D1C3391CCB13E4A80F57166BAC9003031300D060960864801650304020105000420579116B63E065883248C0716DA6A034D23370B321CA080081F4203818E543AC6

这意味着SunMSCAPI虽然为加密操作提供了一个私钥,但是使用公钥部分(我没有详细介绍实现细节来找出这个原因).

所以(AFAIK)SunMSCAPI提供程序不能直接在你的场景中使用…

(请注意,对于每次加密运行,您将获得不同的结果,因为PKCS#1 v1.5加密填充包含随机数据)

幸运的是有一些替代选择:

[A]滥用SunMSCAPI内部API执行这样的签名(再次借助Apache Commons Lang):

// Obtain the handles

long hCryptKey = (Long)MethodUtils.invokeMethod(mscapiPrivKey,"getHCryptKey");

long hCryptProvider = (Long)MethodUtils.invokeMethod(mscapiPrivKey,"getHCryptProvider");

// Call the internal native method

Class> internalClass = Class.forName("sun.security.mscapi.RSASignature");

Method internalSignHashMethod = internalClass.getDeclaredMethod("signHash",boolean.class,byte[].class,int.class,String.class,long.class,long.class);

internalSignHashMethod.setAccessible(true);

byte[] res = (byte[])internalSignHashMethod.invoke(internalClass,false,btHash,btHash.length,"SHA-256",hCryptProvider,hCryptKey);

ArrayUtils.reverse(res); // Make it big endian

>其中的结果与C#代码相同.

>但是强烈依赖于可以随时改变的基础SunMSCAPI实现

[B]使用JNI/JNA直接调用winapi函数

>哪个是一个更清洁的方法,因为它取决于一个公共API

>我找到了this project,但还没有试过

祝你好运!

附录:RSA私钥在示例中使用:

-----BEGIN PRIVATE KEY-----

MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDoZFvkEpdzXwSw

9g6cDxg9n/khCjLIO7E8VQFzu80C0iR0C6K05SHvTFEdssmzZmdCQi092ReSJRPH

yAOQUnlcMuCpi0m62ufZ4yNkZX5sH3fjHkP1FMv5CPtJOIArGFCMS4CufXu2XkXh

dbJuCLPJsUuiRsaoRg0Q6a8QVqWAR1oyVojTNFqzZWTLD46lQQIvINOrIeYvKklU

FUNcmq8PyArwEvxaDeiop4gVyizx7n7v213FjAXMfEG920O4DlnKjObdi1+PhejT

1RUxRUipTmAI2d3JmACpYH6+Il8Ck61wmKQ9IjoTstNeRfKGEkxH9RKP2P4ko5w9

8YfToVDXAgMBAAECggEAI5vNIMNghYMXuu3ZCzyc4ER07gUcBuZun+n+kPdD0JzW

jRmDUuiRLJOrEjvlACI+zD5LpGBxZilcQI57TU/13JTHK/N11rXYNODC+Y07s+GW

gyyOCS2om34u0udfbDsLjJO9If+ER0tmtcdNEeMveUY7aqAhrIMfWWoVMxGzxlXd

0kHWl4blnisjc01xCG4WcXVItyA6F8WZ3kL+BTeR5/3IwM72r9k7fcBkJZPLJZff

oZ2W+whGa9UXAkt6DQ6PlWMvt+AVcu84f8k/4FRRUNbY1OslO7zHbEc1K5qibpjb

6Tlfg2G+bux/1oCJ59bdyRP7FQMmgjLx49H17mwcgQKBgQD1j4HRtwSPnS+INPS4

nVpfEtb+wXGeDLCMAgdesgXYfr5JWJKJCKW65/j2TkJ/xoN8L1z8TeE6o6Q3ZHJ9

QtcM1ifCpNCnjjalbkm9BG4bCPy+5MUIuS5oRtJjwb7mPTxzpq4DIj3G2ooY5F2i

9Nyqde3bEvWn910yqQgI6CjOtwKBgQDyRYkU46gKLhp98gJ0zdm3KNZ/TBE5zsO6

rDnwFPLGxanVNMzkIQX/LXAQOaNK1WD8fmKG+iixDVLyJYtVtuvTQLOHkOOTXw44

QY4BGh+wbS0HrfKd7Qcpt/3HTCKq9eW33+jggyBc+fa+LDIGpdbO16SBCP3Cb7k6

9gtBN5du4QKBgQCKriVO3uGAifESJ3Yd3R/wmZ85+N3FuLzsFSk8XaXXgpzMp2z6

XxvZ1rBPyhrcNqyDMex9wS32A/z2G5BdFaaF5VxHHPWJ61MJUqPqT9ovAoBa/rAY

IR0IXxbqp7y8ItFFL1kPBAOHjlx3emE3arpEup0+IBMEbTsBJV0YSqThOQKBgFRf

syX7QwKIm+FQ71oOdsw7BLjAnR8syy2v3V2nbgWbwVHnWZP5jEUaZfTAngXp2iUV

PusTJCjFIyYBvUzUr7yaw+tqolcou6ML8ZCgsHiZDR2njt9BNUVqNo+6DDjN+nrX

GBtYj2TSCQSiD6oRB4Zxw3DM2NNmZXQLTFAiNDMBAoGBAJOu4+nVB8iUE3JBsrM5

WkwBivqTyo9pusxwEs+GHnkVFsFubFKHda04220JMRVevOuf48DPgvlW6UCTojyr

85dFon9tV0qyi9Ehc0OdXqOjmx0y+wdR6ZqG+x+e6JGiYeReIa4XBrq0cLHlzrNY

8UwL0QLJpuaQZEbqhyOGMNKE

-----END PRIVATE KEY-----

java frf_Java中的方法RSACryptoServiceProvider signHash的等价物相关推荐

  1. Java快速入门学习笔记9 | Java语言中的方法

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  2. JSP中调用java类中的方法

    JSP中调用java类中的方法 1.新建一个项目,在src文件夹下添加一个包:如:test 2.再在包中添加一个类:如 package test; public class conDatabase { ...

  3. Java ArrayList中retainAll()方法具有什么功能呢?

    转自: Java ArrayList中retainAll()方法具有什么功能呢? 下文笔者讲述java中ArrayList方法的功能简介说明,如下所示: retainAll()方法的功能:用于保留 a ...

  4. thymeleaf 调用java,thymeleaf模板引擎调用java类中的方法(附源码)

    前言 由于开源了项目的缘故,很多使用了My Blog项目的朋友遇到问题也都会联系我去解决,有的是把问题留在项目的issue里提出,有的是在我的私人博客里留言,还有的则是直接添加我的qq来找我讲自己遇到 ...

  5. Java集合中contains方法的效率对比

    Java集合中contains方法的效率对比 Java集合List.Set中均有对集合中元素是否存在的判断方法contains(Object o):Map中有对key及value是否存在的判断方法co ...

  6. Java 8 中的方法引用,轻松减少代码量,提升可读性!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 1. 引言 Java8中最受广大开发中喜欢的变化之一是因为 ...

  7. java 只读数组_在Java 8中创建方法引用数组的速记方法?

    我正在使用Wicket 6 / Java 8,并添加了一些简单的类,这些类利用了Java 8中的lambda功能(我知道Wicket的更高版本具有lambda支持,但我们现在不能升级).我正在创建一个 ...

  8. 使用JavaSymbolSolver解决Java代码中的方法调用

    为什么创建java-symbol-solver? 几年前,我开始使用JavaParser ,然后开始做出贡献. 不久之后,我意识到我们想对Java代码执行的许多操作不能仅通过使用解析器生成的抽象语法树 ...

  9. Java接口中的方法和常量

    一.接口是: 接口就是给出一些没有内容的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来. 接口是更加抽象的抽象的类 :抽象类里的方法可以有方法体,接口里的所有方法都没有方法体. ...

最新文章

  1. nginx 的proxy_cache才是王道
  2. python多功能电子钟_python gui - PyQt4 精彩实例分析之电子钟
  3. 开发标准化软件组件能让程序员在大城市过上体面的生活 -- 多系统用户权限管理标准件开发销售心得体会...
  4. 微信公众号 语音转文字api_快速上手——微信公众号开发接入
  5. Nodejs设备接入阿里云IoT平台
  6. centos 测试get请求_centos网站服务器简单性能测试命令
  7. Ubuntu 老版本下载
  8. 第2章 Spring Boot实践,开发社区登录模块(上)
  9. 服务器异常的处理方式
  10. [IMX6Q][Android5.1]移植笔记 --- 无法挂载system文件系统
  11. micropython esp32驱动舵机_关于micropython ESP32的MQTT通讯方式控制舵机
  12. 【Codecs系列】双帧参考特性
  13. 新支点国产服务器操作系统与虚拟化平台和云管理平台实现兼容
  14. P4942 小凯的数字
  15. 英雄联盟手游服务器维护中,《英雄联盟手游》serveriscurrentlyundermaintenance解决攻略...
  16. 会声会影2023旗舰版中文版永久功能使用技巧说明
  17. 统信UOS从虚拟机(BIOS引导)迁移到本机物理机加UEFI改造
  18. Geth命令选项介绍
  19. u盘读不出来怎么修复?数据还能恢复吗?
  20. 用python编写心形字母图案程序讲解

热门文章

  1. 简历制作方面的经验与建议
  2. 微课新鲜出炉了,欢迎大家品评!
  3. [gtalk]gtalk机器人
  4. CSS 设置了line-height等于行高之后文字未垂直居中
  5. Java工厂模式(随笔)
  6. 图像上的算术运算(1)
  7. redis分区(分片)原理
  8. 计算机一级考试选网络题广东,广东计算机一级考试试题
  9. 读书的意义(转载于B站)
  10. java软件项目经验总结_软件项目经验总结