用java编写DES加密、HMAC消息验证和数字签名

        之前学习密码学,老师交给我们做一个试验项目,要求实现jpeg图片的加密、消息验证和数字签名,刚开始学的时候还是一头雾水,现在项目做的差不错了,可以展现给大家看一看了。

 

        闲话不多说,主要看代码,边看代码边讲解思路。

        首先说的是jpeg图片的格式问题,老师希望我们能实现的是部分加密(就是加密DC系数和AC系数中的一部分),但是由于需要解开jpeg图片的哈夫曼编码,太麻烦了,所以我主要用的还是数据的全加密,(这里不懂jpeg图片各个字段的朋友可以先去百度看一下),我所加密的是FFAD字段后面的数据。

        说完jpeg图片问题之后,再次说的就是图片加密和计算HMAC值,因为计算好的MAC需要添加到消息的后面在进行加密,首先看一下加密以及计算MAC的流程图:

160414_VEVT_2544978.png

        第一是读取jpeg图片这个就不多说。将jpeg图片的数据读到一个byte[]中,首先是对这个byte[]进行HMAC计算,计算这个图片的一个MAC值,将计算好的MAC值添加到数据段的后面,然后讲整体进行加密,加密之后传送给接收端,接受断收到消息之后,进行解密,取出解密之后数据的后20个字节(因为计算好的MAC值为20个字节),用前一部分数据在计算一个MAC值,如果两个MAC值相同说明消息没有被修改。

        下面贴出DES加密的class和计算MAC值的class:

        public class EncrypDES {  
      
            //KeyGenerator 提供对称密钥生成器的功能,支持各种算法  
            private KeyGenerator keygen;  
            //SecretKey 负责保存对称密钥  
            private static SecretKey deskey;  
            //Cipher负责完成加密或解密工作  
            private Cipher c;  
            //该字节数组负责保存加密的结果  
            private byte[] cipherByte;  
    
            public static SecretKey getSecretKey(){
                return deskey;
        }
      
    public EncrypDES() throws NoSuchAlgorithmException, NoSuchPaddingException{  
        Security.addProvider(new com.sun.crypto.provider.SunJCE());  
        //实例化支持DES算法的密钥生成器(算法名称命名需按规定,否则抛出异常)  
        keygen = KeyGenerator.getInstance("DES");  
        //生成密钥  
        deskey = keygen.generateKey();  
        //System.out.println("desket :"+deskey);
        //生成Cipher对象,指定其支持的DES算法  
        c = Cipher.getInstance("DES");  ///ECB/NoPadding
    }  
     //加密部分
    public byte[] Encrytor(byte[] src,SecretKey key) throws InvalidKeyException,  
            IllegalBlockSizeException, BadPaddingException {  
        // 根据密钥,对Cipher对象进行初始化,ENCRYPT_MODE表示加密模式  
        c.init(Cipher.ENCRYPT_MODE, key);  
        //byte[] src = str.getBytes();  
        // 加密,结果保存进cipherByte  
        cipherByte = c.doFinal(src);  
        return cipherByte;  
    }  
    //解密部分
    public byte[] Decryptor(byte[] buff,SecretKey key) throws InvalidKeyException,  
            IllegalBlockSizeException, BadPaddingException {  
        // 根据密钥,对Cipher对象进行初始化,DECRYPT_MODE表示加密模式  
        c.init(Cipher.DECRYPT_MODE, key);  
        cipherByte = c.doFinal(buff);  
        return cipherByte;  
    }  

}

 

import javax.crypto.KeyGenerator;  
import javax.crypto.Mac;  
import javax.crypto.SecretKey;  
import javax.crypto.spec.SecretKeySpec;  
import java.security.NoSuchAlgorithmException;  
  

public class HMAC {  
    /** 
     * 定义加密方式 
     */  
    private final static String KEY_MAC = "HmacSHA1";  

  
    /** 
     * 初始化HMAC密钥 
     * @return 
     */  
    public static SecretKey init() {  
        SecretKey key = null;  
        try {  
            KeyGenerator generator = KeyGenerator.getInstance(KEY_MAC);  
            key = generator.generateKey();  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return key;  
    }  
  
    /** 
     * HMAC加密 
     */  
    public static byte[] encryptHMAC(byte[] data, SecretKey key) {  
        byte[] bytes = null;  
        try {  
            Mac mac = Mac.getInstance(key.getAlgorithm());  
            mac.init(key);  
            bytes = mac.doFinal(data);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return bytes;  
    }  
 
 }

        最后说一下进行数字签名。数字签名,顾名思义就是在消息上签上自己的名字,证明这个消息是由发送方发送的,为什么要证明是发送方发送的呢,这个牵扯就比较多了,举一个简单的例子就是,如果A和B有某些合作,由于B的操作失误导致整个合作项目失败了,B为了推卸责任可以伪造一个A给B发送的邮件(或者其他)来说是A让B这么做得,B就会减轻自己的责任。那么A为了证明自己没有发送过这个邮件,就需要验证一下,这个邮件是否有A的签名,如果有的话那就真的是A发送的,如果没有那么说明B在撒谎。

        这只是一个简单的例子,下面我们来直接展示进行数字签名的代码过程:

 

public class MsgSignature {
    
    //1.初始化获得密钥
    public KeyPair init() throws NoSuchAlgorithmException{
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(512);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        return keyPair;
    }
    
    public RSAPrivateKey getPrivateKey(KeyPair keyPair){
        return (RSAPrivateKey)keyPair.getPrivate();
    }
    
    public RSAPublicKey getPublicKey(KeyPair keyPair){
        return (RSAPublicKey)keyPair.getPublic();
    }
    
    //进行签名操作
    public byte[] RSAEncry(byte[] data,RSAPrivateKey rsaPrivateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, 
                                                                                         InvalidKeyException, SignatureException{
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initSign(privateKey);
        signature.update(data);
        byte[] result = signature.sign();
        //System.out.println(result.length+"    "+Hex.encodeHexString(result));
        return result;
    }
    
    //验证签名
    public boolean Check(byte[] data,byte[] result,RSAPublicKey rsaPublicKey) throws InvalidKeySpecException,
                                               NoSuchAlgorithmException, InvalidKeyException, SignatureException{
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(result);
    }
}

 

注:这个项目的源码地址:

       http://www.oschina.net/code/snippet_2544978_56548

转载于:https://my.oschina.net/u/2544978/blog/682919

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值