Java密码学

来源:互联网 发布:沈阳it团队建设 编辑:程序博客网 时间:2024/06/05 05:58

非PKCS7的数字签名

传送门 : https://www.mkyong.com/java/java-digital-signatures-example/

签名的步骤

  1. list存储原文
  2. list储存签名内容
  3. 发送list , 通过ObjectOutputStream直接将list输出

重点代码

    //The method that signs the data using the private key that is stored in keyFile path    public byte[] sign(String data, String keyFile) throws InvalidKeyException, Exception{        Signature rsa = Signature.getInstance("SHA1withRSA");        rsa.initSign(getPrivate(keyFile));        rsa.update(data.getBytes());//和对称加密一样, 用于分块更快        return rsa.sign();    }

验证的过程

  1. ObjectInputStream读取
  2. 读取原文和签名
  3. 进行验证

重点代码

private boolean verifySignature(byte[] data, byte[] signature, String keyFile) throws Exception {        Signature sig = Signature.getInstance("SHA1withRSA");        sig.initVerify(getPublic(keyFile));        sig.update(data);        return sig.verify(signature);    }

PKCS#1签名没有什么特别规定格式.


PKCS7的数字签名

签名需要的参数

  1. 证书(可以一个, 也可以多个, 目的, 让对方知道自己的身份)
  2. 私钥(签名使用)
  3. 原文
  4. 摘要以及加密算法
public static CMSSignedData generateCMSSignedData(PrivateKey privateKey, X509Certificate signCert, byte[] inputData, String algo)throws Exception {        Security.addProvider(new BouncyCastleProvider());//这里我们使用BC的代码库        CMSTypedData msg = new CMSProcessableByteArray(inputData);//        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();        gen.addSignerInfoGenerator(                new JcaSimpleSignerInfoGeneratorBuilder()                        .setProvider("BC")                        .build(algo, privateKey, signCert));//算法可选"SHA1withRSA"        gen.addCertificate(new JcaX509CertificateHolder(signCert));        //gen.addCertificates(new JcaCertStore(Arrays.asList(signCert))); 添加若干个证书时候用        return gen.generate(msg, true);//这里的true和false, 是原文是否要放在CMSSignedData里    }

验签只需要加密文件以及公钥

private void doverify(PublicKey publickey,byte[] data) throws Exception {        Security.addProvider(new BouncyCastleProvider());        CMSSignedData cms = new CMSSignedData(data);//获取签名者所有信息        SignerInformationStore signers = cms.getSignerInfos();        Iterator it = signers.getSigners().iterator();        while (it.hasNext()) {            SignerInformation signer = (SignerInformation) it.next();            if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder() .setProvider("BC").build(publickey))) {                System.out.println("verified");                System.out.println();            }        }    }

这里或许你会好奇, 为什么不需要原文, 因为原文已经被包含在里面了

CMSSignedData cms=...CMSTypedData signedContent = cms.getSignedContent();System.out.println(new String((byte[])signedContent.getContent()));//获得原文数据

有几个类需要注意

  1. CMSTypedData : CMS里变成类型的数据, 也就是不是raw , byte[]形式
  2. CMSProcessableByteArray实现CMSTypedData : CMS hold数据,用于被处理

前辈告诉我们, 要学会看ASN.1格式, 我们尝试通过这个ASN.1, 看看能否得到代码思路

- Signed Datasigned-data PKCS7-CONTENT-TYPE ::= {SignedData                                    IDENTIFIED BY  id-signed-data}SignedData ::= SEQUENCE {  version           Version,  digestAlgorithms  DigestAlgorithmIdentifiers,  contentInfo       ContentInfo,  certificates      [0]  CertificateSet OPTIONAL,  crls              [1]  CertificateRevocationLists OPTIONAL,  signerInfos       SignerInfos}SignerInfo ::= SEQUENCE {  version                    Version,  signerIdentifier           SignerIdentifier,  digestAlgorithm            DigestAlgorithmIdentifier,  authenticatedAttributes    [0]  Attributes OPTIONAL,  digestEncryptionAlgorithm  DigestEncryptionAlgorithmIdentifier,  encryptedDigest            EncryptedDigest,  unauthenticatedAttributes  [1]  Attributes OPTIONAL}
  1. 获得signedData(可预测)
  2. 获得signerInfo(多少可尝试到)
  3. 如何验证(这一点, 我们无法预测), 这一点, 看ASN.1无法完成, 需要提前了解签名的原理

相比之下, 签名却没有如此规律. 结论 : 当我们要提出数据时候, 看ASN.1还是有点用.

生成签名等, 难找规律, 不过也是有一些规律

  1. 获取数据, 转换成专门的类
  2. 丢进生成器 , 生成器有时候还装一些生成器的实现类
原创粉丝点击