Java中加解密简单应用分析
发布日期:2021-05-27 02:54:22 浏览次数:4 分类:技术文章

本文共 12179 字,大约阅读时间需要 40 分钟。

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

在对称加密中常用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+RpROTmdXQtaE5mu97tjoNQDES对称加密算法

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

 

转载地址:https://blog.csdn.net/leijie0322/article/details/113845573 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Java中ThreadLocal浅析
下一篇:Java常用设计模式之策略模式

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2023年11月16日 18时10分08秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章