Java密码学 非对称加密以及使用secp256k1进行数字签名(ECDSA),也适合Android(下)

1. 概述


上篇讲述了秘钥的生成、存储和加载,这篇的内容就是如何生成和校验数字签名。

2. Signature类


在Java中,签名和校验,都是通过: Signature 类来实现的。

该类的主要方法如下:

  • getInstance(String algorithm)

工厂方法,获取Signature实例,而参数:algorithm就是签名算法的名称,这里我们使用的是:SHA256withECDSA

更具体的参数,请浏览:https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#Signature

  • initSign(PrivateKey privateKey)
  • initVerify(PublicKey publicKey)

初始化成签名或者校验,Signature类的实例,在同一个阶段只能完成签名或者校验之一的任务,因此调用initSign或者initVeify让Signature进入相应的状态

  • update(byte[] data)

无论是计算签名,还是校验数据,都需要传入被签名或者被校验的数据,调用该方法进行计算。注意,该方法可以调用多次,通常数据都可能非常大,不可能一次性读入内存(从磁盘上或者网络),因此我们可以对数据进行分块,一次性一KB或者合适的块进行多次调用

  • sign()

获取签名,当所有的数据都调用update计算后,就可以获取签名了,返回的签名是一个byte数组

  • verify(byte[] signature)

校验签名,当所有的数据都调用update计算之后,调用该方法,传递签名数据,如果签名正确,那么返回true,否则返回false,说明数据可能被篡改、伪造,或者对应的私钥不正确。

3. 实例


Java中计算签名比较简单,请阅读下面代码中的注释

public static byte[] signData(String algorithm, byte[] data, PrivateKey key) throws Exception {
        Signature signer = Signature.getInstance(algorithm);
        signer.initSign(key);
        signer.update(data);
        return (signer.sign());
    }

    public static boolean verifySign(String algorithm, byte[] data, PublicKey key, byte[] sig) throws Exception {
        Signature signer = Signature.getInstance(algorithm);
        signer.initVerify(key);
        signer.update(data);
        return (signer.verify(sig));
    }

    @Test
    public void testSignVerify() throws Exception {
        // 需要签名的数据
        byte[] data = new byte[1000];
        for (int i=0; i<data.length; i++)
            data[i] = 0xa;

        // 生成秘钥,在实际业务中,应该加载秘钥
        KeyPair keyPair = KeyUtil.createKeyPairGenerator("secp256k1");
        PublicKey publicKey1 = keyPair.getPublic();
        PrivateKey privateKey1 = keyPair.getPrivate();

        // 生成第二对秘钥,用于测试
        keyPair = KeyUtil.createKeyPairGenerator("secp256k1");
        PublicKey publicKey2 = keyPair.getPublic();
        PrivateKey privateKey2 = keyPair.getPrivate();

        // 计算签名
        byte[] sign1 = signData("SHA256withECDSA", data, privateKey1);
        byte[] sign2 = signData("SHA256withECDSA", data, privateKey1);

        // sign1和sign2的内容不同,因为ECDSA在计算的时候,加入了随机数k,因此每次的值不一样
        // 随机数k需要保密,并且每次不同


        // 用对应的公钥验证签名,必须返回true
        Assert.assertTrue(verifySign("SHA256withECDSA", data, publicKey1, sign1));
        // 数据被篡改,返回false
        data[1] = 0xb;
        Assert.assertFalse(verifySign("SHA256withECDSA", data, publicKey1, sign1));
        data[1] = 0xa;
        
        Assert.assertTrue(verifySign("SHA256withECDSA", data, publicKey1, sign1));
        // 签名被篡改,返回false
        // 签名为DER格式,前三个字节是标识和数据长度,如果修改了这三个会抛出异常,无效签名格式
        sign1[20] = (byte)~sign1[20];
        Assert.assertFalse(verifySign("SHA256withECDSA", data, publicKey1, sign1));

        // 使用其他公钥验证,返回false
        Assert.assertFalse(verifySign("SHA256withECDSA", data, publicKey2, sign1));
    }

我们在测试用例中可以看到,只要是数据、签名被修改,或者不正确的私钥都会引发签名验证失败.

4. 签名输出数据解析


针对 SHA256withECDSA ,输出的是DER编码的签名数据,长度并非固定,但是是70到72字节,之所以会这样是因为,SHA256withECDSA 签名输出实际是两个32字节的大整数(r和s),在转换成byte[]的时候,如果为负数,那么会添加前导位0,如果当r和s都是正数,那么就是64个字节,都是负数,就是66字节。而DER编码还会包含类型以及长度字段,因此总长度就会到70到72字节。一般情况下,传输DER编码的签名值没多大问题,但如果对数据量要求十分严格,例如在BLE上传输,可以提取出r和s再打包传输

5. 参考


  1. Java SE 7 Security Documentation
  2. 数字签名是什么?
  3. Android签名机制之---签名过程详解
  4. ECC加密算法入门介绍
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容