Java中加解密简单应用分析

在日常开发中的安全测试或安全功能研发时经常遇到加解密,涉及到对称加密和非对称加密。

在对称加密中常用DES(data encrption standard)算法和AES算法

DES:DES 加密算法是一种分组密码,以 64 位为分组对数据加密,它的密钥长度是 56 位,加密解密用同一算法。DES 加密算法是对密钥进行保密,而公开算法,包括加密和解密算法。这样,只有掌握了和发送方相同密钥的人才能解读由 DES 加密算法加密的密文数据。因此,破译 DES 加密算法实际上就是搜索密钥的编码。对于 56 位长度的密钥来说,如果用穷举法来进行搜索的话,其运算次数为 2 的 56 次方。

public class DES {

    private final static String DES = "DES";

    public static void main(String[] args) throws Exception {
        String data = "DES对称加密算法";
        String key = "asdfghjkl123456789"; //秘钥设置的长度必须大于等于 8
        System.err.println(encrypt(data, key));
        System.err.println(decrypt(encrypt(data, key), key));
    }

    /**
     * Description 根据键值进行加密
     */
    public static String encrypt(String data, String key) throws Exception {
        byte[] bt = encrypt(data.getBytes(), key.getBytes());
        String strs = new BASE64Encoder().encode(bt);
        return strs;
    }

    /**
     * Description 根据键值进行解密
     */
    public static String decrypt(String data, String key) throws IOException, Exception
    {
        if (data == null) {
            return null;
        }
        BASE64Decoder decoder = new BASE64Decoder();
        byte[] buf = decoder.decodeBuffer(data);
        byte[] bt = decrypt(buf,key.getBytes());
        return new String(bt);
    }

    /**
     * Description 根据键值进行加密
     */
    private static byte[] encrypt(byte[] data, byte[] key) throws Exception {
        // 生成一个可信任的随机数源
        SecureRandom sr = new SecureRandom();
        // 从原始密钥数据创建DESKeySpec对象
        DESKeySpec dks = new DESKeySpec(key);
        // 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
        SecretKey securekey = keyFactory.generateSecret(dks);
        // Cipher对象实际完成加密操作
        Cipher cipher = Cipher.getInstance(DES);
        // 用密钥初始化Cipher对象
        cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
        return cipher.doFinal(data);
    }

    /**
     * Description 根据键值进行解密
     */
    private static byte[] decrypt(byte[] data, byte[] key) throws Exception {
        // 生成一个可信任的随机数源
        SecureRandom sr = new SecureRandom();
        // 从原始密钥数据创建DESKeySpec对象
        DESKeySpec dks = new DESKeySpec(key);
        // 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
        SecretKey securekey = keyFactory.generateSecret(dks);
        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance(DES);
        // 用密钥初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
        return cipher.doFinal(data);
    }
}
//打印
JozfxOVCs+RpROTmdXQtaE5mu97tjoNQ
DES对称加密算法

AES:AES 加密算法是密码学中的高级加密标准,该加密算法采用对称分组密码体制,密钥长度的最少支持为 128、192、256,分组长度 128 位,算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的区块加密标准,AES 标准用来替代原先的 DES,已经被多方分析且广为全世界所使用。

public class AES {

    private final static String AES = "AES";

    private final static String ALGORITHM = "AES/ECB/PKCS5Padding";


    public static void main(String[] args) throws Exception {
        // 此处使用AES-128-ECB加密模式,key需要为16位。
        String cKey = "1234567890123456";
        // 需要加密的字串
        String cSrc = "DES对称加密算法";
        System.out.println("原文是:" + cSrc);
        // 加密
        String enString = Encrypt(cSrc, cKey);
        System.out.println("加密后的字串是:" + enString);
        // 解密
        String DeString = Decrypt(enString, cKey);
        System.out.println("解密后的字串是:" + DeString);
    }

    // 加密
    public static String Encrypt(String sSrc, String sKey) throws Exception {
        if (sKey == null) {
            System.out.print("Key为空null");
            return null;
        }
        // 判断Key是否为16位
        if (sKey.length() != 16) {
            System.out.print("Key长度不是16位");
            return null;
        }
        byte[] raw = sKey.getBytes("utf-8");
        SecretKeySpec skeySpec = new SecretKeySpec(raw, AES);
        Cipher cipher = Cipher.getInstance(ALGORITHM);//"算法/模式/补码方式"
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));

        return new Base64().encodeToString(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。
    }

    // 解密
    public static String Decrypt(String sSrc, String sKey) throws Exception {
        try {
            // 判断Key是否正确
            if (sKey == null) {
                System.out.print("Key为空null");
                return null;
            }
            // 判断Key是否为16位
            if (sKey.length() != 16) {
                System.out.print("Key长度不是16位");
                return null;
            }
            byte[] raw = sKey.getBytes("utf-8");
            SecretKeySpec skeySpec = new SecretKeySpec(raw, AES);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] encrypted1 = new Base64().decode(sSrc);//先用base64解密
            try {
                byte[] original = cipher.doFinal(encrypted1);
                String originalString = new String(original,"utf-8");
                return originalString;
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }
}
//打印
原文是:DES对称加密算法
加密后的字串是:dT8DU7s8uAWviSBWHA7F5I2aeUSqIXpF6I7CxbmTzY4=
解密后的字串是:DES对称加密算法

在非对称加密中常用RSA算法

RSA:生成密钥,介绍3中方法

  • 命令行:可以使用openssl进行生成公钥和私钥。
-- 生成公钥和私钥openssl genrsa -out key.pem 1024        -out 指定生成文件,此文件包含公钥和私钥两部分,所以即可以加密,也可以解密        1024 生成密钥的长度
  • 使用网站:生成密钥的网站,百度一下
  • 使用代码:可以指定生成密钥的长度,最低是 512。
public static KeyPair buildKeyPair() throws NoSuchAlgorithmException {    final int keySize = 2048;    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);    keyPairGenerator.initialize(keySize);    return keyPairGenerator.genKeyPair();}
public class RSA {

    private static final Base64.Decoder decoder = Base64.getDecoder();
    private static final Base64.Encoder encoder = Base64.getEncoder();

    public static void main(String[] args) throws Exception {
        KeyPair keyPair = buildKeyPair();
        String message = "RSA非对称加密算法";
        byte[] encryptData = encrypt(keyPair.getPublic(), message);
        System.out.println(String.format("加密后的数据:%s",base64Encode(encryptData)));
        System.out.println(String.format("解密后的数据:%s",new String(decrypt(keyPair.getPrivate(),encryptData),"utf-8")));

        String context = "加签的字符串";
        String sign = signWithRSA(context, keyPair.getPrivate());
        System.out.println(String.format("生成的签名:%s",sign));
        Boolean checkSignWithRSA = checkSignWithRSA(context, keyPair.getPublic(), sign);
        System.out.println(String.format("校验的结果:%s",checkSignWithRSA.toString()));
    }

    /**
     * 生成密钥对
     */
    public static KeyPair buildKeyPair() throws NoSuchAlgorithmException {
        final int keySize = 2048;
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(keySize);
        return keyPairGenerator.genKeyPair();
    }

    /**
     * 加密
     */
    public static byte[] encrypt(PublicKey publicKey, String message) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(message.getBytes("utf-8"));
    }

    /**
     * 解密
     */
    public static byte[] decrypt(PrivateKey privateKey, byte [] encrypted) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(encrypted);
    }

    /**
     * 使用RSA签名
     */
    private static String signWithRSA(String content, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA1WithRSA");
        signature.initSign(privateKey);
        signature.update(content.getBytes("utf-8"));
        byte[] signed = signature.sign();
        return base64Encode(signed);
    }

    /**
     * 使用RSA验签
     */
    private static boolean checkSignWithRSA(String content, PublicKey publicKey,String sign) throws Exception {
        Signature signature = Signature.getInstance("SHA1WithRSA");
        signature.initVerify(publicKey);
        signature.update(content.getBytes("utf-8"));
        return signature.verify(base64Decode(sign));
    }

    private static String base64Encode(byte[] signed) {
        //编码
        String encodedText = encoder.encodeToString(signed);
        return encodedText;
    }

    private static byte[] base64Decode(String sign) throws UnsupportedEncodingException {
        //解码
        byte[] decode = decoder.decode(sign);
        return decode;
    }

}
//打印
加密后的数据:j56URGDJjS2Meo3P698aj3JqZKKpOJIOghTawsdi1+ASQb9FgsC2QDPF/w78aghIo0SEY6Q7H7p2Slys/wH1VW5zFfy5/IdK6CK44nvnHMs+NmodCJrSeimoZnuFC92WRqryWgSC2l25pGaHrEVcR5jR7V6Mk8677TyUpDjyHPIPwAHBUVn8mydxKR0BtgP2J5pvFZJip7T+5sPavGixKLHHgRC+B660OHwPOGUXfvaNDjN6l5crSQlfNMBep9dzKLh/22RQHUVf8HkKTwR38LQM+sNvR23RE8q+Q2W/+mEx5WZLkXBBlcRQ4Ww/UvkmmADIxuurblUBtkP0mENEzw==
解密后的数据:RSA非对称加密算法
生成的签名:WezHTvgJExCvAL1gJbEsfAOVntzFac9FDmtX3qa1BO33QwHWOKGbsdH2Drk2MIVWS1db7grqwifi4w60tzH0Q7SU1iCJ1TOcQR4EI3PbIsY9VkLD+nRRyJKyTRstN8S+saJDV5NIzA9wb7x170DsIaUphLslU1XQR1Y0c7HY4WklzMfQ25kLIc7ocJP29tzknEnkcElqQVwxiGNIZehWmmHJZ2JMcbdTtLZEMtW5FC3pEhrvUtrEwENWhc4g8Dvix9LrSVoxPmRslMeL8ldHj5Ec4UsXR4mZldBKpdc5PO8oo6HbIFP2eX14ACpPFCQQnAjtQZ+9TOP/KuDzXduClQ==
校验的结果:true

加签和验签

公钥是用来解密信息的,确保让别人知道这条信息是真的由我发布的,是完整正确的。接收者由此可知这条信息确实来自于拥有私钥的某人,这被称作数字签名,公钥的形式就是数字证书。所以这种我们称之为加签验签。举例,银行 A 发布了一个银行客户端的补丁供所有用户更新,那为了确保人家下载的是正确完整的客户端,银行A会为这个程序打上一个数字签名(就是用银行A的私钥对这个程序加密然后发布),你需要在你的电脑里装上银行 A 的数字证书(就是银行对外发布的公钥),然后下载好这个程序,数字证书会去解密这个程序的数字签名,解密成功,补丁得以使用。同时你能知道这个补丁确实是来自这个银行 A,是由他发布的,而不是其他人发布的。

摘要算法常用MD5算法

数据摘要算法是密码学算法中非常重要的一个分支,它通过对所有数据提取指纹信息以实现数据签名、数据完整性校验等功能,由于其不可逆性,有时候会被用做敏感信息的加密。数据摘要算法也被称为哈希(Hash)算法或散列算法。

public class MD5 {

    public static void main(String[] args) {
        String message = "123456789";
        try {
            String md5Str = getMD5Str(message);
            System.out.println(md5Str);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String getMD5Str(String str) throws Exception {
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md.update(str.getBytes());
            // digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
            return new BigInteger(1, md.digest()).toString(16);
        } catch (Exception e) {
            throw new Exception("MD5加密出现错误,"+e.toString());
        }
    }

}
// 打印
25f9e794323b453885f5181f1b624d0b

public class MD5Util {

    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

    public static void main(String[] args) {
        String sign = "3ae14696f82a547cfce841651b67342a1";
        String message = "摘要";
        String signature = encode(message);
        System.out.println(signature);
        boolean flag = signature.equals(sign);
        Assert.isTrue(flag, "签名错误");
    }

    public static String encode(String origin) {
        return encode(origin, "UTF-8");
    }

    public static String encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname)) {
                resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
            } else {
                resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
            }
        } catch (Exception exception) {

        }
        return resultString;
    }

    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n += 256;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }
}
// 打印
3ae14696f82a547cfce841651b67342a

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值