java 安全加密api(cipher,signature,mac...)

[TOC]

前言

本文主要讲解常用加密算法,消息摘要,二进制字符变换等的java实现,对于加密算法本身的原理只会做简单的介绍,详细的原理可百度。

相关概念

  • 加密

加密是指将可读取的明文作为输入,通过特定的变换操作得到不易读取的输出(通常是二进制序列),目前常用的加密算法包括 对称加密的AES/DES,非对称加密的RSA/DSA/EC加密很重要的一点就是解密,无论多复杂的数学变换,一定可以通过相应的逆变换得到原始输入,这是的加密行为才有意义。

  • hash(哈希变换)

hash值又称散列值或者消息摘要,对输入的字符串或者二进制序列通过一定的变换得到固定长度的输出,它是一个不可逆的过程,理解这个不可逆的过程可以从数学中的求余函数理解,例如:11/10 = 1 ... 1余数是1,以除以10作为变换,余数1作为输出,不可能通过余数是1得到被除数是11,因为有可能是21、31、41。。。。。。等等,同时和求余类似,hash碰撞指的就是不同的输入可能得到相同的输出。当然对于真正的hash变换,不可能像求余过程如此简单,但是这个不可逆过程的原理是类似的。常用的hash变换有MD5/SHA1/HmacSHA1/HmacMD5....等,hash变换的目的并不是让输入不可读取,而是让输入不可改变。

  • 字节变换

文件通常会分为文本文件和二进制文件,文本文件通过(Unicode/UTF-8/ASCII)编码之后是可以读取的,而二进制文件是不可读的,因为部分数值没有对应的编码。但是在开发过程中,很多时候需要将不可读的二进制数据转成可读的字符串进行传输,因此就有了字节变换操作,常用的字节变换操作有Base64,UrlEncoder,还有通过将二进制转成十六进制字符进行变换,在MD5和SHA1变换中常用。字节变换最主要的目的是:将不易读取或者不易传输的数据转成易读取或者易传输的字符串

相关api介绍

java中对于加密的支持api都在java.securityjavax.crypto包下,主要用到的类有:

Cipher

主要用于加密行为,如进行AES/DES/RSA等加密行为

  • 初始化对象static Cipher getInstance(String transformation)

transformation的组成可以概括为algorithm/mode/padding,algorithm用于指定加密的方式,mode用于指定特定加密方式的变换模式,padding是字节填充规则。modepadding可以不写,可用的transformation组合有:

//括号数值为所需秘钥的长度
AES/CBC/NoPadding (128)
AES/CBC/PKCS5Padding (128)
AES/ECB/NoPadding (128)
AES/ECB/PKCS5Padding (128)
DES/CBC/NoPadding (56)
DES/CBC/PKCS5Padding (56)
DES/ECB/NoPadding (56)
DES/ECB/PKCS5Padding (56)
DESede/CBC/NoPadding (168)
DESede/CBC/PKCS5Padding (168)
DESede/ECB/NoPadding (168)
DESede/ECB/PKCS5Padding (168)
RSA/ECB/PKCS1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)
  • 初始化参数void init(int opmode, Key key)

opmode用于指定该对象是要进行加密还是解密,key是加密所用的秘钥信息。

  • 加密方法byte[] doFinal(byte[] input)

cipher.doFinal(byte[] input)等同于cipher.update(byte[] input); cipher.doFinal();

示例代码:

  1. AES加解密
@org.junit.Test
public void testCipherAES() throws Exception {
    //指定使用AES加密
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    //使用KeyGenerator生成key,参数与获取cipher对象的algorithm必须相同
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
    //指定生成的密钥长度为128
    keyGenerator.init(128);
    Key key = keyGenerator.generateKey();
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] bytes = cipher.doFinal("helloworld".getBytes());
    System.out.println("AES加密: " + Base64.getEncoder().encodeToString(bytes));

    //由于AES加密在CBC模式下是需要有一个初始向量数组byte[] initializeVector ,
    // 而解密的时候也需要同样的初始向量,因此需要使用加密时的参数初始化解密的cipher,否则会出错
    byte[] initializeVector = cipher.getIV();
    IvParameterSpec ivParameterSpec = new IvParameterSpec(initializeVector);
    cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);
    //上面三步操作可以用此操作代替   cipher.init(Cipher.DECRYPT_MODE, key, cipher.getParameters());
    bytes = cipher.doFinal(bytes);
    System.out.println("AES解密: " + new String(bytes));
}


//输出
AES加密: pRy4ZbW7qgZ33iWBJ60BDA==
AES加密: helloworld
  1. DES加解密
@org.junit.Test
public void testCipherDES() throws Exception {
    //指定使用DES加密
    Cipher cipher = Cipher.getInstance("DES");
    //使用KeyGenerator生成key,参数与获取cipher对象的algorithm必须相同
    KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
    //DES的秘钥长度必须是56位
    keyGenerator.init(56);
    Key key = keyGenerator.generateKey();
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] bytes = cipher.doFinal("helloworld".getBytes());
    System.out.println("DES加密: " + Base64.getEncoder().encodeToString(bytes));
    //与AES不同,由于DES并不需要初始向量,因此解密的时候不需要第三个参数
    cipher.init(Cipher.DECRYPT_MODE, key);
    bytes = cipher.doFinal(bytes);
    System.out.println("DES解密: " + new String(bytes));
}

//输出
DES加密: XoG4lEjZN4VBlZYTXjw6BQ==
DES解密: helloworld
  1. RSA加解密
@org.junit.Test
public void testCipherRSA() throws Exception {
    //获取cipher对象
    Cipher cipher = Cipher.getInstance("RSA");
    //通过KeyPairGenerator来生成公钥和私钥
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(1024);
    KeyPair keyPair = keyPairGenerator.generateKeyPair();

    PublicKey publicKey = keyPair.getPublic();//公钥
    PrivateKey privateKey = keyPair.getPrivate();//私钥

    /*加密*/
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] bytes = cipher.doFinal(TEXT.getBytes());
    final String encryptText = Base64.getEncoder().encodeToString(bytes);
    System.out.println("RSA公钥加密:" + encryptText);

    /*解密*/
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    bytes = cipher.doFinal(Base64.getDecoder().decode(encryptText));
    System.out.println("RSA解密:" + new String(bytes));
}

//输出
RSA公钥加密:bKbbpARpcHcCqcMdGmA/WzvyO2G3eXFJhmrK5F0yFlJsoGohg4XIq5egNc1eBQwP7BRD6m7c12byB/KpYNgWg7J5Y3kupWBahZyhJ7SWWF0YY9CrdWf55zQ/CPyn+KlWQg1ViBnIBnejABFuqjDgBmZ3Q3txT1tD4MIpGPCE+NY=
RSA私钥解密:helloworld

Mac

该类主要用作Hmac运算,初始化方法Mac.getInstance(String algorithm)的可用参数有

HmacMD5
HmacSHA1
HmacSHA224
HmacSHA256
HmacSHA384
HmacSHA512

示例代码

@org.junit.Test
public void testHmac() throws Exception {
    Mac mac = Mac.getInstance("HmacMD5");
    //第一个参数可以是任意字符串,第二个参数与获取Mac对象的algorithm相同
    SecretKeySpec secretKeySpec = new SecretKeySpec("123456".getBytes(), "HmacMD5");
    mac.init(secretKeySpec);
    byte[] bytes = mac.doFinal("helloworld".getBytes());
    System.out.println("HmacMD5结果:" + HexUtil.toHexString(bytes));

    mac = Mac.getInstance("HmacSHA1");
    mac.init(new SecretKeySpec("123456".getBytes(), "HmacSHA1"));
    bytes = mac.doFinal("helloworld".getBytes());
    System.out.println("HmacSHA1结果:" + HexUtil.toHexString(bytes));
}

//输出
HmacMD5结果:2449233556af565ecbb2fd6266df853b
HmacSHA1结果:ef9079b9e2e79c67a962f87e2a87af4f35c2ae37

Signature

signature类用于提供数字签名,用于保证数据的完整性
示例代码,Signature.getInstance(String algorithm)的可用参数有

NONEwithRSA
MD2withRSA
MD5withRSA
SHA1withRSA
SHA224withRSA
SHA256withRSA
SHA384withRSA
SHA512withRSA
NONEwithDSA
SHA1withDSA
SHA224withDSA
SHA256withDSA
NONEwithECDSA
SHA1withECDSA
SHA224withECDSA 
SHA256withECDSA
SHA384withECDSA
SHA512withECDSA

示例代码:

@org.junit.Test
public void testSignature() throws Exception {
   
    Signature signature = Signature.getInstance("NONEwithRSA");

    //KeyPairGenerator生成公钥和私钥
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(1024);
    KeyPair keyPair = keyPairGenerator.generateKeyPair();

    PublicKey publicKey = keyPair.getPublic();
    PrivateKey privateKey = keyPair.getPrivate();

    //用私钥初始化signature
    signature.initSign(privateKey);
    //更新原始字符串
    signature.update(TEXT.getBytes());
    byte[] bytes = signature.sign();
    String sign = Base64.getEncoder().encodeToString(bytes);
    System.out.println("数字签名: " + sign);


    //用公钥初始化signature
    signature.initVerify(publicKey);
    //更新原始字符串
    signature.update(TEXT.getBytes());
    //校验签名是否正确
    boolean result = signature.verify(Base64.getDecoder().decode(sign));

    System.out.println("签名校验结果: " + result);
}

MessageDigest

MessageDigest主要是做hash变换(也称消息摘要或者散列值)

示例代码:

 @org.junit.Test
public void testMessageDigest() throws Exception {
    //参数可以是 MD5,MD2,MD5,SHA-1,SHA-224,SHA-256,SHA-384,SHA-512
    MessageDigest messageDigest = MessageDigest.getInstance("MD5");
    byte[] bytes = messageDigest.digest("helloworld".getBytes());
    //将二进制数组转成16进制字符串输出
    System.out.println("MD5哈希变换:" + HexUtil.toHexString(bytes));


    messageDigest = MessageDigest.getInstance("SHA-1");
    bytes = messageDigest.digest("helloworld".getBytes());
    System.out.println("SHA1哈希变换:" + HexUtil.toHexString(bytes));
}

//HexUtil
public static String toHexString(byte[] data) {
    StringBuilder builder = new StringBuilder();
    int len = data.length;
    String hex;
    for (int i = 0; i < len; i++) {
        hex = Integer.toHexString(data[i] & 0xFF);
        if (hex.length() == 1) {
            builder.append("0");
        }
        builder.append(hex);
    }
    return builder.toString();
}


//输出 可以通过标准在线工具检验输出结果的准确性
MD5哈希变换:fc5e038d38a57032085441e7fe7010b0
SHA1哈希变换:6adfb183a4a2c94a2f92dab5ade762a47889a5a1

KeyGenerator

用于生成秘钥, KeyGenerator.getInstance(String algorithm)支持的参数有

AES (128)
DES (56)
DESede (168)
HmacSHA1
HmacSHA256

示例代码

@org.junit.Test
public void testKeyGenerator() throws Exception {
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
    //初始化方法有多种,根据需要选择
    keyGenerator.init(128);
//      keyGenerator.init(new SecureRandom("1234567".getBytes()));
    
    SecretKey key = keyGenerator.generateKey();
    //key的二进制编码   将它保存到文件中

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, key);

    byte[] bytes = cipher.doFinal("helloworld".getBytes());

    System.out.println("加密数据: " + Base64.getEncoder().encodeToString(bytes));

    /*=========保存key的二进制编码=========*/
    byte[] keyBytes = key.getEncoded();
    FileOutputStream fos = new FileOutputStream("F://test/key.txt");
    fos.write(keyBytes);
    fos.flush();
    fos.close();


    /*============从文件中读取编码并恢复key==============*/
    FileInputStream fis = new FileInputStream("F://test/key.txt");
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    int len;
    byte[] buffer = new byte[1024];
    while ((len = fis.read(buffer)) > 0) {
        bos.write(buffer, 0, len);
    }
    fis.close();

    /*==============使用SecretKeySpec重新生成key============*/
    SecretKeySpec secretKeySpec = new SecretKeySpec(bos.toByteArray(), "AES");

    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, cipher.getParameters().getParameterSpec(IvParameterSpec.class));
    bytes = cipher.doFinal(bytes);
    System.out.println("解密数据: " + new String(bytes));
}

//输出
加密数据: 0vUaeC2VWEvVpUWeDfgGhg==
解密数据: helloworld

KeyPairGenerator

KeyPairGenerator用于生成一对密钥对,用于做非对称加密操作。KeyPairGenerator.getInstance(String alorithm)的可用参数为:

DSA
RSA
EC

代码生成的密钥对通常需要将公钥和私钥保存到文件中,这样才能够持久化进行操作,下面演示两种保存的实现

  1. 分别保存公钥和私钥的二进制编码
@org.junit.Test
public void testSaveKeyPair2() throws Exception {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(1024);
    KeyPair keyPair = keyPairGenerator.generateKeyPair();

    PublicKey oldPbk = keyPair.getPublic();
    PrivateKey oldPrk = keyPair.getPrivate();

    Cipher cipher = Cipher.getInstance("RSA");
    /*============使用原始私钥加密,重新生成的公钥解密===============*/
    cipher.init(Cipher.ENCRYPT_MODE, oldPrk);
    byte[] bytes = cipher.doFinal("helloworld".getBytes());
    System.out.println("原始私钥加密: " + Base64.getEncoder().encodeToString(bytes));

    /*提取公钥的比特编码经过Base64转换后保存到文件,注意公钥的比特编码是X.509格式*/
    byte[] pbks = Base64.getEncoder().encode(oldPbk.getEncoded());
    File file = new File("F://test/public.key");
    FileOutputStream fos = new FileOutputStream(file);
    fos.write(pbks);
    fos.flush();
    fos.close();

    /*从文件中提取公钥比特编码并恢复成公钥*/
    file = new File("F://test/public.key");
    FileInputStream fis = new FileInputStream(file);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len;
    while ((len = fis.read(buffer)) > 0) {
        bos.write(buffer, 0, len);
    }
    pbks = Base64.getDecoder().decode(bos.toByteArray());
    X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(pbks);
    //重新得到公钥
    PublicKey newPbk = KeyFactory.getInstance("RSA").generatePublic(encodedKeySpec);


    cipher.init(Cipher.DECRYPT_MODE, newPbk);
    bytes = cipher.doFinal(bytes);
    System.out.println("新的公钥解密: " + new String(bytes));

      /*============使用原始公钥加密,重新生成的私钥解密===============*/
    cipher.init(Cipher.ENCRYPT_MODE, oldPbk);
    bytes = cipher.doFinal("helloworld".getBytes());
    System.out.println("原始私钥加密: " + Base64.getEncoder().encodeToString(bytes));


    /*省略了文件存取操作,与公钥相同*/

    byte[] prks = oldPrk.getEncoded();
    /*私钥的比特编码是pkcs8格式*/
    PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(prks);
    PrivateKey newPrk = KeyFactory.getInstance("RSA").generatePrivate(pkcs8EncodedKeySpec);
    cipher.init(Cipher.DECRYPT_MODE, newPrk);
    bytes = cipher.doFinal(bytes);
    System.out.println("新的私钥解密: " + new String(bytes));
}
//输出
原始私钥加密: CO7FU1hQsEd8fYV4ZfWXquo/qrktte2n/WakdHJuw001aa9RM/mYl6yC6jLMGlm0fxuYlH92Zv9jA7k/0TVuor8Csvzmbm00RMBhnQCme+aQQbSoZDZEwJj1HtW6aK5MJRI4l/1W+g5X+Fs/6TLlbXpJM0k4epGMKUWwhO6cUiM=
新的公钥解密: helloworld
原始私钥加密: ixqqoM3aRig3P6GGPICsSOdH8KXRrlFn9GB1OVIWt46Q9ROsS84BW693fKB9ea8CnLJayc2KU1yhPlHHqq08gU8WOxVYeBQ4Bi3MnoJzUluE/UWNaMYZt/jCB6NZx57XEpNJ6uKG5TUmZJm+eoK0BF7A8sOX96UbPuZlHd4lD0w=
新的私钥解密: helloworld
  1. 保存密钥对的特征值 公钥(N,e)私钥(N,d)
 @org.junit.Test
public void testSaveKeyPair() throws Exception {
    final String algorithm = "RSA";
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);

    keyPairGenerator.initialize(1024);

    KeyPair keyPair = keyPairGenerator.generateKeyPair();

    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

    /*特征值N  e   d*/

    BigInteger N = publicKey.getModulus();
    BigInteger e = publicKey.getPublicExponent();
    BigInteger d = privateKey.getPrivateExponent();

    /**/
    String nStr = Base64.getEncoder().encodeToString(N.toByteArray());
    String eStr = Base64.getEncoder().encodeToString(e.toByteArray());
    String dStr = Base64.getEncoder().encodeToString(d.toByteArray());

    /*将这三个字符串保存到文件或者数据库,通常n,e可以保存在客户端,而n,d的数据必须保存在服务端*/


    N = new BigInteger(Base64.getDecoder().decode(nStr));
    e = new BigInteger(Base64.getDecoder().decode(eStr));
    d = new BigInteger(Base64.getDecoder().decode(dStr));

     /*根据N,e生成公钥*/
    RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(N, e);
    PublicKey pbk = KeyFactory.getInstance(algorithm).generatePublic(publicKeySpec);

    Cipher cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.ENCRYPT_MODE, pbk);
    //bytes 是加密后的数据
    byte[] bytes = cipher.doFinal("helloworld".getBytes());
    //用base64转换输出
    System.out.println("加密数据:" + Base64.getUrlEncoder().encodeToString(bytes));

     /*根据N,d生成私钥*/
    RSAPrivateKeySpec ps = new RSAPrivateKeySpec(N, d);
    PrivateKey prk = KeyFactory.getInstance(algorithm).generatePrivate(ps);

    cipher.init(Cipher.DECRYPT_MODE, prk);
    bytes = cipher.doFinal(bytes);
    System.out.println("解密数据:" + new String(bytes));
}

//输出
加密数据:nVqRtqMDvnm-4pjW0R1Q6sRCRbLpK4WRtG342ydEa8069Kv2OVRGE1Rm3iEFZjFCyh_z_0jlf5liqCgDCkN9I2Ci1qWvrvQo9wZKQG5g86OrxWHs7n1Kg_SXR3rNC-55jPxQAYUXpw-U9XX4ls7aQ85pk2BMZLYoRbwo3ktZAxM=
解密数据:helloworld

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

推荐阅读更多精彩内容

  • 概述 之前一直对加密相关的算法知之甚少,只知道类似DES、RSA等加密算法能对数据传输进行加密,且各种加密算法各有...
    Henryzhu阅读 3,001评论 0 14
  • 介绍 加密和解密都使用同一把秘钥,这种加密方法称为对称加密,也称为单密钥加密。简单理解为:加密解密都是同一把钥匙 ...
    Blizzard_liu阅读 793评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,591评论 18 139
  • 最近工作忙碌劳累,导致心情极差,吃的也不是很健康总之老想发火骂人特别容易情绪激动对同事不满最终请了两天假,第一我在...
    格物11致知阅读 194评论 0 0
  • 完成事项:2, 未完成事项:1,原因:晚上很困,把孩子哄睡后快十点了,迷迷糊糊睡着了,没有做复盘,因为早上有读书计...
    泡沫XY阅读 86评论 0 0