java实现数字(摘要)签名,生成签名文件,防止文件被人篡改内容,分析和实现

实现自定义的签名工具,我们需要java.security.*的类实现

现在签名一般以非对称加密方式为主。
什么是非对称加密?

非对称加密:把密钥分为公钥和私钥,公钥是公开的所有人都可以认领,私钥是保密的只有一个人知道。
公钥加密:对内容本身加密,保证不被其他人看到。
私钥加密:证明内容的来源
公钥和私钥是配对关系,公钥加密就用私钥解密,反之亦然,用错的密钥来尝试解密会报错。

整理思路:

1.获取一个秘钥对
关键对象:
.KeyPairGenerator//秘钥对构造器
SecureRandom//系统随机源
PublicKey//公钥,实现了java.security.Key接口
PrivateKey//私钥,实现了java.security.Key接口

2.根据私钥进行生成签名文件
关键对象:
java.security.Signature//签名对象,有哪些步骤?–>初始化秘钥,然后更新签名目标,然后签名
PKCS8EncodedKeySpec //通过KeyFactory验证私钥自身编码

3.根据公钥进行签名文件验证
关键对象:
java.security.Signature//签名对象,有哪些步骤?–>初始化秘钥,然后更新验证目标,然后根据签名进行验证
X509EncodedKeySpec //通过KeyFactory验证公钥自身编码

实现

1.获取一个秘钥对(RSA)
工具类:
:主要方法

 /**
     * 生成公钥、私钥
     *
     * @param seed 种子
     * @return 返回公钥、私钥,第一个是公钥、第二个是私钥
     */
    public static String[] generatorKeys(String seed) {
        String[] results = new String[2];
        String priKey;
        String pubKey;
        java.security.KeyPairGenerator keygen;
        try {
            // RSA秘钥对
            keygen = java.security.KeyPairGenerator.getInstance(SIGN_ALGORITHM);
            // 系统随机源
            SecureRandom secrand = new SecureRandom();
            secrand.setSeed(seed.getBytes());
            // 初始化为1024长度
            keygen.initialize(1024, secrand);
            KeyPair keys = keygen.genKeyPair();

            PublicKey pubkey = keys.getPublic();
            PrivateKey prikey = keys.getPrivate();

            // 秘钥字节数组转换
            pubKey = bytesToHex(pubkey.getEncoded());
            priKey = bytesToHex(prikey.getEncoded());

            results[0] = pubKey;
            results[1] = priKey;
            System.out.println("生成秘钥成功");
        } catch (NoSuchAlgorithmException e) {
            System.out.println("生成秘钥失败");
            e.printStackTrace();
        }
        return results;
    }

两个个二进制与16进制互转的方法:

/**
     * 16string->bytes2
     * Transform the specified Hex String into a byte array.
     */
    public static final byte[] hexToBytes(String s) {

        byte[] bytes;

        bytes = new byte[s.length() / 2];

        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) Integer.parseInt(s.substring(2 * i, 2 * i + 2),
                    16);
        }

        return bytes;
    }

    /**
     * bytes2->16string
     * Transform the specified byte into a Hex String form.
     */
    public static final String bytesToHex(byte[] bcd) {

        StringBuffer s = new StringBuffer(bcd.length * 2);

        for (int i = 0; i < bcd.length; i++) {
            // 移位和与运算
            s.append(bcdLookup[(bcd[i] >>> 4) & 0x0f]);
            // 与运算
            s.append(bcdLookup[bcd[i] & 0x0f]);
        }

        return s.toString();
    }

2.根据私钥进行生成签名文件

:签名方法

 /**
     * 完成签名
     *
     * @param contentDigest 要签名的摘要(处理大文件)
     * @param priKey        私钥
     * @return
     * @throws Exception
     */
    private static final String signKey(String contentDigest, String priKey) throws Exception {

        // 实例化秘钥工厂
        KeyFactory keyFactory = null;
        try {
            keyFactory = KeyFactory.getInstance(KeyPairUtil.SIGN_ALGORITHM);
            // PKCS8EncodedKeySpec用于私钥编码ASN.1
            PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(KeyPairUtil.hexToBytes(priKey));
            //得到私钥对象
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8);
            // 获得SIGN_ALGORITHMS的签名对象
            java.security.Signature signature = java.security.Signature.getInstance(KeyPairUtil.SIGN_ALGORITHMS);
            // 初始化秘钥(私钥签名)
            signature.initSign(privateKey);
            // 更新待签名
            signature.update(contentDigest.getBytes("utf-8"));
            // 签名
            byte[] signResult = signature.sign();
            // 返回特殊的16进制串(签名)
            return KeyPairUtil.bytesToHex(signResult);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("签名失败");
        }

    }

3.根据公钥进行签名文件验证
:验证方法

  /**
     * 完成签名的验证
     *
     * @param fileContentDigest 要验证的原文摘要(处理大文件)
     * @param signContent
     * @param pubKey
     * @return
     * @throws Exception
     */
    private static final boolean validKey(String fileContentDigest, String signContent, String pubKey) throws Exception {
        // 实例化秘钥工厂
        KeyFactory keyFactory = null;
        try {
            keyFactory = KeyFactory.getInstance(SIGN_ALGORITHM);
            // X509EncodedKeySpec用于公钥编码ASN.1
            X509EncodedKeySpec x509 = new X509EncodedKeySpec(KeyPairUtil.hexToBytes(pubKey));
            //得到公钥对象
            PublicKey publicKey = keyFactory.generatePublic(x509);
            // 获得SIGN_ALGORITHMS的签名检查对象
            java.security.Signature signatureCheck = java.security.Signature.getInstance(KeyPairUtil.SIGN_ALGORITHMS);
            // 初始化秘钥(公钥检查)
            signatureCheck.initVerify(publicKey);
            // 更新待验证
            signatureCheck.update(fileContentDigest.getBytes("utf-8"));
            // 签名验证
            return signatureCheck.verify(KeyPairUtil.hexToBytes(signContent));

        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("文件签名验证异常");
        }

    }

剩下的主要是:
1.将签名保存为一个文件,供下次验证。
2.写一个摘要产生方式做签名目标,以应对大文件的签名。
多是文件的读写

本文仅提供思路

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值