常用加密解密算法【RSA、AES、DES、MD5】介绍和使用

2023-11-18

为了防止我们的数据泄露,我们往往会对数据进行加密,特别是敏感数据,我们要求的安全性更高。下面将介绍几种常用的加密算法使用。这些算法的加密对象都是基于二进制数据,如果要加密字符串就使用统一编码(如:utf8)进行编码后加密。

1.摘要算法

常用的摘要算法有MD5,SHA1。摘要算法是一个不可逆过程,就是无论多大数据,经过算法运算后都是生成固定长度的数据,一般结果使用16进制进行显示。
MD5和SHA1的区别:MD5结果是128位摘要,SHa1是160位摘要。那么MD5的速度更快,而SHA1的强度更高。

下面统一使用MD5算法进行说明,SHA1类似。
主要用途有:验证消息完整性,安全访问认证,数据签名。

  • 消息完整性:由于每一份数据生成的MD5值不一样,因此发送数据时可以将数据和其MD5值一起发送,然后就可以用MD5验证数据是否丢失、修改。
  • 安全访问认证:这是使用了算法的不可逆性质,(就是无法从MD5值中恢复原数据)对账号登陆的密码进行MD5运算然后保存,这样可以保证除了用户之外,即使数据库管理人员都无法得知用户的密码。
  • 数字签名:这是结合非对称加密算法和CA证书的一种使用场景。

一般破解方法:字典法,就是将常用密码生成MD5值字典,然后反向查找达到破解目的,因此建议使用强密码。

MD5的使用—对文件进行摘要。

    //对文件进行MD5摘要
    public static String getMD5(String path){
        String pathName = path;
        String md5= "";
        try {
            File file = new File(pathName);
            FileInputStream ins = new FileInputStream(file);
            FileChannel ch = ins.getChannel();
            MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,file.length());       
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(byteBuffer);
            ins.close();
            md5 = toHexString(md.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return md5;
    }
    //以16进制编码进行输出
    final static char hex[] = {
    
    '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    public static String toHexString(byte[] tmp){
        String s;
        char str[] = new char[tmp.length*2];
        int k =0;
        for (int i = 0; i < tmp.length; i++) {
            byte byte0 = tmp[i];
            str[k++] = hex[byte0>>>4&0xf];
            str[k++] = hex[byte0&0xf];
        }
        s=new String(str);
        return s;
    }

SHA1的使用


    //对文件进行SHA1摘要
    public static String getSHA1(String path){
        String pathName = path;
        String sha1= "";
        try {
            File file = new File(pathName);
            FileInputStream ins = new FileInputStream(file);
            FileChannel ch = ins.getChannel();
            MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,file.length());       
            MessageDigest sha = MessageDigest.getInstance("SHA-1");
            sha.update(byteBuffer);
            ins.close();
            sha1 = toHexString(sha.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sha1;
    }

可以发现我们的关键代码就是

    MessageDigest sha = MessageDigest.getInstance("SHA-1");
    sha.update(byteBuffer);
    ins.close();
    byte[] r = sha.digest());

只是不同的算法初始化时不同罢了。MessageDigest.getInstance("SHA-1")
另外还可以使用

DigestUtils.sha1(data);
DigestUtils.md5Hex(data);

上面实现使用的是Apache下面的一个加解密开发包commons-codec
官方地址为:http://commons.apache.org/codec/
官方下载地址:http://commons.apache.org/codec/download_codec.cgi

2.对称加密算法

对称加密算法只是为了区分非对称加密算法。其中鲜明的特点是对称加密是加密解密使用相同的密钥,而非对称加密加密和解密时使用的密钥不一样。对于大部分情况我们都使用对称加密,而对称加密的密钥交换时使用非对称加密,这有效保护密钥的安全。非对称加密加密和解密密钥不同,那么它的安全性是无疑最高的,但是它加密解密的速度很慢,不适合对大数据加密。而对称加密加密速度快,因此混合使用最好。
常用的对称加密算法有:AES和DES.

  • DES:比较老的算法,一共有三个参数入口(原文,密钥,加密模式)。而3DES只是DES的一种模式,是以DES为基础更安全的变形,对数据进行了三次加密,也是被指定为AES的过渡算法。
  • AES:高级加密标准,新一代标准,加密速度更快,安全性更高(不用说优先选择)

AES的使用

AES密钥长度可以选择128位【16字节】,192位【24字节】和256位【32字节】密钥(其他不行,因此别乱设密码哦)。

    /**使用AES对字符串加密
     * @param str utf8编码的字符串
     * @param key 密钥(16字节)
     * @return 加密结果
     * @throws Exception
     */
    public static byte[] aesEncrypt(String str, String key) throws Exception { 
           if (str == null || key == null) return null; 
           Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
           cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES")); 
           byte[] bytes = cipher.doFinal(str.getBytes("utf-8")); 
           return  bytes;
       } 
    /**使用AES对数据解密
     * @param bytes utf8编码的二进制数据
     * @param key 密钥(16字节)
     * @return 解密结果
     * @throws Exception
     */
       public static String aesDecrypt(byte[] bytes, String key) throws Exception { 
           if (bytes == null || key == null) return null; 
           Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
           cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES")); 
           bytes = cipher.doFinal(bytes);
           return new String(bytes, "utf-8"); 
       } 

上面代码是对字符串进行的加解密。但要注意的是AES算法的所有参数都是字节码的(包括密钥)。因此字符串字符需要转换成字节码后进行加密str.getBytes("utf-8")按照字符串的编码进行转换。另外参数:”AES/ECB/PKCS5Padding”在加密和解密时必须相同,可以直接写”AES”,这样就是使用默认模式(C#和java默认的模式不一样,C#中默认的是这种,java的默认待研究)。分别的意思为:AES是加密算法,ECB是工作模式,PKCS5Padding是填充方式。
AES是分组加密算法,也称块加密。每一组16字节。这样明文就会分成多块。当有一块不足16字节时就会进行填充。
一共有四种工作模式:

  • ECB 电子密码本模式:相同的明文块产生相同的密文块,容易并行运算,但也可能对明文进行攻击。
  • CBC 加密分组链接模式:一块明文加密后和上一块密文进行链接,不利于并行,但安全性比ECB好,是SSL,IPSec的标准。
  • CFB 加密反馈模式:将上一次密文与密钥运算,再加密。隐藏明文模式,不利于并行,误差传递。
  • OFB 输出反馈模式:将上一次处理过的密钥与密钥运算,再加密。隐藏明文模式,不利于并行,有可能明文攻击,误差传递。

PKCS5Padding的填充方式是差多少字节就填数字多少;刚好每一不足16字节时,那么就会加一组填充为16.还有其他填充模式【Nopadding,ISO10126Padding】(不影响算法,加密解密时一致就行)。

DES的使用

和AES类似,指定为DES就行。3DES指定为”DESede”,DES密钥长度是56位,3DES加长了密钥长度,可以为112位或168位,所以安全性提高,速度降低。工作模式和填充模式标准和AES一样。

    /**使用DES对字符串加密
     * @param str utf8编码的字符串
     * @param key 密钥(56位,7字节)
     * @return 加密结果
     * @throws Exception
     */
    public static byte[] desEncrypt(String str, String key) throws Exception { 
           if (str == null || key == null) return null; 
           Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); 
           cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "DES")); 
           byte[] bytes = cipher.doFinal(str.getBytes("utf-8")); 
           return  bytes;
       } 
    /**使用DES对数据解密
     * @param bytes utf8编码的二进制数据
     * @param key 密钥(16字节)
     * @return 解密结果
     * @throws Exception
     */
       public static String desDecrypt(byte[] bytes, String key) throws Exception { 
           if (bytes == null || key == null) return null; 
           Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); 
           cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "DES")); 
           bytes = cipher.doFinal(bytes);
           return new String(bytes, "utf-8"); 
       } 

3.非对称加密(RSA)

这里主要对RSA进行介绍。
对称加密加密解密使用的是相同的密钥,而非对称加密加密解密时使用的不同的密钥,分为公钥(public key)和私钥(private key).公钥可以公开,而私钥自己保存。它利用的是两个大质数相乘十分容易,而对其乘积进行因素分解十分困难。这样就可以将乘积作为密钥了,这个乘积为N值,根据两个大质数选择e和生成d,删掉两个大质数。这样(N,e)为公钥,(N,d)为私钥,公钥无法破解出私钥(不作详细介绍,我们不是研究算法的)。由于非对称加密的密钥生成麻烦,所以无法做到一次一密,而且其加密速度很慢,无法对大量数据加密。因此最常用的使用场景就是数字签名和密码传输,用作数字签名时使用私钥加密,公钥解密;用作加密解密时,使用公钥加密,私钥解密。

需要注意的是RSA加密是有长度限制的,1024位密钥可以加密128字节(1024位),不满128字节的使用随机数填充,但是RSA实现中必须要加随机数(11字节以上),所以明文长度最大为117字节,然后剩下的加入随机数。这也产生了每次加密结果每一次都不一样的特点。

如果明文长度超过限制怎么办?

  • 1.可以与对称加密混合使用,一次一密产生对称加密的密钥,然后使用此密钥进行数据对称加密,再使用RSA私钥对对称密钥加密,一起保存。解密时使用公钥解密出密钥,然后进行数据解密。
  • 2.可以分段加密。将明文按117字节分成多段,加密后再拼接起来。由于每一段密文长度都是128字节,所以解密时按照128字节分段解密。

java的RSA密钥生成与使用

简单使用

下面是java中的使用方法,先是生成密钥对,然后加密,再解密。需要注意的是这个方法是不能跨语言使用的,因为里面对公钥和私钥用到的序列化是java的序列化。
由于加密后的密文都是字节码形式的,我们要以字符串方式保存或传输的话,可以使用Base64编码。

public class RSAUtil {
     
     
    /** 指定加密算法为RSA */
    private static String ALGORITHM = "RSA";
    /*指定加密模式和填充方式*/
    private static String ALGORITHM_MODEL = "RSA/ECB/PKCS1Padding";
    /** 指定key的大小,一般为1024,越大安全性越高 */
    private static int KEYSIZE = 1024;
    /** 指定公钥存放文件 */
    private static String PUBLIC_KEY_FILE = "PublicKey";
    /** 指定私钥存放文件 */
    private static String PRIVATE_KEY_FILE = "PrivateKey";
    /**
     * 生成密钥对
     */
    private static void generateKeyPair() throws Exception {
        /** RSA算法要求有一个可信任的随机数源 */
        SecureRandom sr = new SecureRandom();
        /** 为RSA算法创建一个KeyPairGenerator对象 */
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
        /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
        kpg.initialize(KEYSIZE, sr);
        /** 生成密匙对 */
        KeyPair kp = kpg.generateKeyPair();
        /** 得到公钥 */
        Key publicKey = kp.getPublic();
        /** 得到私钥 */
        Key privateKey = kp.getPrivate();
        /** 用对象流将生成的密钥写入文件 */
        ObjectOutputStream oos1 = new ObjectOutputStream(new FileOutputStream(
                PUBLIC_KEY_FILE));
        ObjectOutputStream oos2 = new ObjectOutputStream(new FileOutputStream(
                PRIVATE_KEY_FILE));
        oos1.writeObject(publicKey);
        oos2.writeObject(privateKey);
        /** 清空缓存,关闭文件输出流 */
        oos1.close();
        oos2.close();
    }
    /**
     * 加密方法 source: 源数据
     */
    public static byte[] encrypt(String source) throws Exception {
        /** 将文件中的公钥对象读出 */
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                PUBLIC_KEY_FILE));
        Key key = (Key) ois.readObject();
        ois.close();
        /** 得到Cipher对象来实现对源数据的RSA加密 */
        Cipher cipher = Cipher.getInstance(ALGORITHM_MODEL);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] b = source.getBytes();
        /** 执行加密操作 */
        byte[] b1 = cipher.doFinal(b);
        return b1;
    }
    /**
     * 解密算法 cryptograph:密文
     */
    public static String decrypt(byte[] cryptograph) throws Exception {
        /** 将文件中的私钥对象读出 */
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                PRIVATE_KEY_FILE));
        Key key = (Key) ois.readObject();
        /** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
        Cipher cipher = Cipher.getInstance(ALGORITHM_MODEL);
        cipher.init(Cipher.DECRYPT_MODE, key);
        /** 执行解密操作 */
        byte[] b = cipher.doFinal(cryptograph);
        return new String(b);
    }
    public static void main(String[] args) throws Exception {
        generateKeyPair();//生成密钥对
        String source = "Hello World!";// 要加密的字符串
        byte[] cryptograph = encrypt(source);// 生成的密文
        //可以将密文进行base64编码进行传输
        System.out.println(new String(Base64.encode(cryptograph)));
        String target = decrypt(cryptograph);// 解密密文
        System.out.println(target);
    }
}

RSA密钥使用Base64编码

要灵活使用肯定不能使用java的序列化保存了,我们对上面的generateKeyPair()方法进行改写。通过密钥生成器生成公钥,私钥后,调用publicKey.getEncoded()和privateKey.getEncoded(),此时它生成的比特编码是有独特格式的(公钥是X.509,私钥是PKCS#8)可以使用publicKey.getFormat(),privateKey.getFormat();进行查看。之后对字节码进行Base64编码就行了。

密钥生成方法

    //以base64编码密钥
    public Map<String ,String> generateKeyPair1() throws Exception{
        SecureRandom sr = new SecureRandom();
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(1024, sr);
        KeyPair kp = kpg.generateKeyPair();
        Key publicKey = kp.getPublic();
        Key privateKey = kp.getPrivate();
        byte[] pb = publicKey.getEncoded();
        String pbStr =  new String(Base64.encode(pb));
        byte[] pr = privateKey.getEncoded();
        String prStr =  new String(Base64.encode(pr));
        Map<String, String> map = new HashMap<String, String>();
        map.put("publicKey",pbStr);
        map.put("privateKey", prStr);
        return map;
    }

恢复密钥方法,使用各自不同的编码形式恢复

    //从base64编码的公钥恢复公钥
    public PublicKey getPulbickey(String key_base64) throws Exception{
        byte[] pb = Base64.decode(key_base64).getBytes();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pb);
        KeyFactory  keyfactory = KeyFactory.getInstance("RSA");
        return keyfactory.generatePublic(keySpec);
    }
    //从base64编码的私钥恢复私钥
    public PrivateKey getPrivatekey(String key_base64) throws Exception{
        byte[] pb = Base64.decode(key_base64).getBytes();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pb);
        KeyFactory  keyfactory = KeyFactory.getInstance("RSA");
        return keyfactory.generatePrivate(keySpec);
    }

加密解密方法都类似下面,PrivateKey和PublicKey是Key的子接口。

    /** 执行加密操作 */
    public static byte[] encrypt(Key key,byte[] source) throws Exception{
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] ciphertext = cipher.doFinal(source);
        return ciphertext;
    }
    /** 执行加密操作 */
    public static byte[] decrypt(Key key,byte[] ciphertext) throws Exception{
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] source = cipher.doFinal(ciphertext);
        return source;
    }

记录RSA的密钥特征值并进行密码恢复

所谓特征值就是RSA中公钥(N,e)私钥(N,d)的三个值:N,e,d。只要有这三个值我们就可以恢复密钥了。这是实际开发中常用的方法。首先是提取特征值,我们需要将PublicKey强制转换为RSAPublicKey.然后获取,看代码。

    //提取特征值保存,以base64编码密钥
        public static Map<String ,String> generateKeyPair2() throws Exception{
            SecureRandom sr = new SecureRandom();
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(1024, sr);
            KeyPair kp = kpg.generateKeyPair();
            Key publicKey = kp.getPublic();
            Key privateKey = kp.getPrivate();
            RSAPublicKey rpk = (RSAPublicKey)publicKey;
            RSAPrivateKey rpr= (RSAPrivateKey)privateKey;
            //三个特征值都是BigInteger类型。
            BigInteger N = rpk.getModulus();//N值
            BigInteger e = rpk.getPublicExponent();//e值
            BigInteger d  = rpr.getPrivateExponent();//d值
            Map<String, String> map = new HashMap<String, String>();
            //将BigInteger转为byte[],然后以base64保存
            map.put("N",new String(Base64.decode(N.toByteArray())));
            map.put("e", new String(Base64.decode(e.toByteArray())));
            map.put("d", new String(Base64.decode(d.toByteArray())));
            return map;
        }

利用三个特征值就可以非常容易恢复密钥了。

    //从base64编码的特征值(N,e)恢复公钥
        public static PublicKey getPulbickey(String N_Str,String e_Str) throws Exception{
            BigInteger N = new BigInteger(1, Base64.decode(N_Str.getBytes()));
            BigInteger e = new BigInteger(1, Base64.decode(e_Str.getBytes()));
            KeyFactory kf = KeyFactory.getInstance("RSA");
            RSAPublicKeySpec ps = new RSAPublicKeySpec(N, e);
            PublicKey pkey = kf.generatePublic(ps);
            return pkey;
        }
    //从base64编码的特征值(N,d)恢复私钥
    public static PrivateKey getPrivatekey(String N_Str,String d_Str) throws Exception{
        BigInteger N = new BigInteger(1, Base64.decode(N_Str.getBytes()));
        BigInteger d = new BigInteger(1, Base64.decode(d_Str.getBytes()));
        KeyFactory kf = KeyFactory.getInstance("RSA");
        RSAPrivateKeySpec ps = new RSAPrivateKeySpec(N, d);
        PrivateKey pkey = kf.generatePrivate(ps);
        return pkey;
    }

C#生成的密钥java中使用–记录特征值的例子

C#生成的公钥是保存在xml文件中的,使用的是Base64编码,因此我们先解析出密钥对象,然后再使用公钥加密,而让C#端服务器进行解密。Modulus就是N值,Exponent就是e值,然后组成(N,e)公钥。
C#的密钥形式如:

<RSAKeyValue>
<Modulus>7gFGAUTUBiSi8j+oZ4JY4NUNCfdGIxFLhKE0c4SbiHvNAiD7rxWnmuqXK4nVzOyjJsmCViA1aRN3+Tf5xMqxtjjCKWNRWAp5LMp2AfL3DrDcWV/ZjwPIUO52yEa+q2PyJ0OMgRxBA80WWBzv+EJm7/rq8wP9gpVI+HY0ACH8Kmk=
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
//从xml中获取公钥
    public static PublicKey getPublicKey(String xmlkey) throws Exception {
        Document doc = XmlUtil.parseXml(xmlkey);
        Node node = doc.getChildNodes().item(0);
        NodeList list = node.getChildNodes();
        String e = null, m = null;
        for (int i = 0; i < list.getLength(); i++) {
            String nodename = list.item(i).getNodeName();
            String value = list.item(i).getTextContent();
            if (nodename.equals("Modulus")) {
                e = value;
            } else if (nodename.equals("Exponent")) {
                m = value;
            }
        }
        BigInteger b1 = new BigInteger(1, Base64.decode(e.getBytes()));
        BigInteger b2 = new BigInteger(1, Base64.decode(m.getBytes()));
        System.out.println(b1 + "\n" + b2);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        RSAPublicKeySpec ps = new RSAPublicKeySpec(b1, b2);
        PublicKey pkey = kf.generatePublic(ps);
        return pkey;
    }
    //RSA加密
    public static byte[] encrypt(byte[] data,PublicKey publickey) {
        if (publickey == null || data == null) {
            return null;
        }
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, publickey);
            return cipher.doFinal(data);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    //字符串转Document
    public static Document parseXml(String str) throws ParserConfigurationException, SAXException, IOException{
        StringReader reader = new StringReader(str);
        InputSource source = new InputSource(reader);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(source);
    }

4.编码的使用

常见的编码有Base64,HEX和对URL的编码。这都是为了实际需要才进行的编码。HEX是编码成16进制字符,MD5一般就是以HEX进行编码,这不说了。

Base64

Base64一开始是为了解决邮件中不能传文件和图片问题而使用的,将无法阅读的二进制码转化成字符形式,字符为(A-Za-z0-9+/)。它的原理是将3个8位字节(24位)转化为4个6位字节(24位),之后在6位的前面补两个0,形成8位一个字节形式,如果剩下的不足3字节,则用0填充,输出字符使用”=”,所以编码后文本可能出现1个或2个’=’.这样就将原本3个字节变成了4个字节,那就是64种编码了。当然,除了对二进制数据编码,还可以对字符串编码来隐藏明文,让别人不那么容易看懂。
由于jdk中的base64是不开发使用了 ,所有需要下载到网上下载Base64包,我使用的是 javaBase64-1.2.jar,另外android sdk中是带有base64的,位置是android.util.Base64

/*这里使用的是android.util.base64*/
byte[] input = "hello world".getBytes("utf8");
//编码    
byte[] encodeData = Base64.encode(input , 0);
//解码        
byte[] result = Base64.decode(encodeData , 0);

URL的编码

url一般使用的都是英文、数字和某些符号,而对于特殊符号,中文等这些是不允许使用的。因此我们要在url请求中加入特殊符号,中文等就需要对它们进行编码。http请求时,url部分是必须编码的,get的请求字段可以不进行url编码。比如
http://www.baidu.com/中文?wd=国际
“中文”必须进行url编码,“国际”可以不用。
那url编码到底是怎么进行编码的呢?
都是在16进制前面加上‘%’表示。对于一些字符使用的是”%xx”,而对于中文,就是多个”%xx%xx%xx”,xx的数字有编码的16进制决定(没有指定字符编码(utf8),则使用默认编码),然后每一字节前面加”%”。
Android 中提供的URL编码解码方法。

String d = URLEncoder.encode('中文'"utf8");
String f = URLDecoder.decode("%20");

RSA参考文章:
【1】 RSA算法使用介绍
【2】使用X.509数字证书加密解密实务(二)– 证书的获得和管理

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

常用加密解密算法【RSA、AES、DES、MD5】介绍和使用 的相关文章

  • java 拖放

    我尝试熟悉java中的拖放 但我发现的所有教程都是 让我生气 我想要的只是从 JList 包含在名为 UserPanel 的自制 JPanel 中 拖动 PublicUserLabel 并将其放入从 JTabbedPanel 继承的自制类中
  • 如何将webview内容划分为多个页面

    我必须使用 Android 上的 PdfDocument 从 webView 创建 PDF https developer android com reference android graphics pdf PdfDocument htm
  • 清空变量不会使方法引用无效[重复]

    这个问题在这里已经有答案了 为什么代码不抛出NullPointerException当我使用与变量绑定的方法引用时dog我后来分配了null to 我正在使用 Java 8 import java util function Functio
  • 传递自定义类型查询参数

    如何接受自定义类型查询参数 public String detail QueryParam request final MYRequest request 上面的行在启动服务器时出现错误 jersey server model ModelV
  • 当前平台不支持桌面 API

    我遇到过这个错误 java lang UnsupportedOperationException 当前平台不支持桌面 API 我将从我的 java 应用程序中打开一个文件 我用这个方法 Desktop getDesktop open new
  • Spring 从 JBoss 上下文加载 PropertySourcesPlaceholderConfigurer

    我有一个使用 PropertySourcesPlaceholderConfigurer 的 spring 3 1 应用程序加载设置 我想管理测试和生产环境 只需从服务器上下文加载设置覆盖本地文件属性中指定的设置 下一个示例在 Tomcat
  • Google 表格使用 API 密钥而不是 client_secret.json

    In the QuickStart java示例Java 快速入门 https developers google com sheets api quickstart java他们使用OAuth client ID识别该应用程序 这会弹出一
  • 如何检查单词是否在wordNet中

    我开始了解wordNet直到我知道我找到了synonymous对于一个特定的词 现在我有一个文件 我想使用标记化该文本n gram例如 String s I like to wear tee shirt 使用后n gram这将是 I lik
  • 在 Eclipse 中删除空块之前的新行

    我更喜欢奥尔曼式 http en wikipedia org wiki Brace style Allman style大括号 例如 if foo magical prancing unicorn stuff 而不是 if foo unma
  • java彩色滚动条搜索结果

    我将如何在 Java 中自定义滚动条 以便我可以进行像 chrome 一样的搜索 也就是说在结果所在的位置放置彩色条纹 我不想要一个库 因为我更喜欢自己编写代码 另外 我不想失去我拥有的 L F 欢迎举例 实际上 它将查看一个大的文本文件或
  • 始终将双精度舍入

    我怎么总是能把一个double to an int 并且永远不要将其四舍五入 我知道Math round double 但我希望它始终向上舍入 所以如果是的话3 2 四舍五入为 4 您可以使用Math ceil method 请参阅Java
  • React Native v0.71.8 React-native-vector-icons 你看不到的图标

    我在用react native版本v0 71 8 我安装了react native vector icons库 但图标未显示 似乎链接在最新版本的 React Native 中不再起作用 所以我按照说明进行操作 但它不再编译 出现以下错误
  • 获取接收者的设备令牌以在 Firebase 中发送通知

    所以我正在学习如何使用 firebase 发送设备到设备的通知 我看到了这个answer https stackoverflow com a 42548586 5237289发送通知 看起来很简单 现在 我知道要获取发件人的令牌 它应该如下
  • 向Java类库添加函数

    我使用的 Java 类库在很多方面都不完整 有很多类我认为应该内置其他成员函数 但是 我不确定添加这些成员函数的最佳实践 让我们调用不足的基类A class A public A long arbitrary arguments publi
  • 如何使用 AffineTransform.quadrantRotate 旋转位图?

    我想旋转一个bitmap关于它的中心点 然后将其绘制成更大的图形上下文 位图是40x40 pixels 图形上下文是500x500 pixels 这就是我正在做的 BufferedImage bi new BufferedImage 500
  • 如何在一次操作中使用 Thymeleaf 检查 null 和空条件?

    有什么方法可以检查 Thymeleaf 中的 null 和empty 条件吗 方法一 1 variable1 variable2 variable3 2 variable null 3 variable 如果我们结合两个条件 例如 vari
  • 在 Tensorflow-lite Android 中将位图转换为 ByteBuffer(浮点)

    在用于图像分类的tensorflow lite android演示代码中 图像首先转换为ByteBuffer格式以获得更好的性能 这种从位图到浮点格式的转换以及随后到字节缓冲区的转换似乎是一个昂贵的操作 循环 按位运算符 float mem
  • 如何更改 JAX-WS Web 服务的地址位置

    我们目前已经公开了具有以下 URL 的 JAX RPC Web 服务 http xx xx xx xx myservice MYGatewaySoapHttpPort wsdl http xx xx xx xx myservice MYGa
  • 用于生成 ISO 文件的 Maven 插件

    有没有可以生成ISO镜像的maven插件 我需要获取一些模块的输出 主要是包含 jar 的 zip 文件 并将它们组合成一个 ISO 映像 Thanks 现在有一个 ISO9660 maven 插件可以完成这项工作 https github
  • JPA ManyToMany 产生的空联接表

    我有一个应用程序 其中我尝试使用 Hibernate 作为 JPA 提供程序来实现两个实体之间的多对多关系 我正在尝试的例子是一个单向的 其中一个相机可以有多个镜头 而镜头可以安装到多个相机中 以下是我的实体类 只需粘贴其中的相关部分 Ca

随机推荐

  • Acwing2554. 排列数

    在一个排列中 一个折点是指排列中的一个元素 它同时小于两边的元素 或者同时大于两边的元素 对于一个 1 n 的排列 如果可以将这个排列中包含 t 个折点 则它称为一个 t 1 单调序列 例如 排列 1 4 2 3 是一个 3 单调序列 其中
  • SDN/NFV标准组织&SDN架构

    标准组织 1 ONF 开放网络基金会 2 ODL OpenDayLight 3 ETSI 欧洲电信标准协会 作为标准制定的依据 2012年成立 由运营商主导 通信设备 信息设备等厂家共同参与 推动NFV标准研究和产业进程的临时性组织 4 I
  • ERP的灵魂

    ERP应该是有灵魂的 这个灵魂就是规划 开发和完善时的理念 用土话说 上ERP到底是为了啥 有了灵魂 ERP的开发和实施就不会摇摆不定 灵魂源于初心 要回归本源 注意这个本源不是数字化 也不是上档升级 这些只是手段 结果或目的 而不是本源
  • 内容多,鼠标略过显示内容

    格式化单元格提示信息 function formatCellTooltip value return span title value span th 异常类型 th
  • knime工具介绍(1)

    本文旨在介绍knime在数据分析中可具体扮演的角色 安利给大家这个超好用数据分析工具 截图部分转自亚洲数析协会公开课截图 如有侵权请及时私信处理 因为内容比较多 先慢慢更新 未完待续9 14 一 数据分析的全流程均可以用到这个工具 台湾数析
  • 解决:修改JAVA_HOME后,Java版本无法正常切换

    经验总结 步骤1 检查路径是否正确 步骤2 将JAVA HOME配置到path最前面 步骤3 删除 C ProgramData Oracle Java javapath 目录下三个 exe 文件 步骤4 重新测试是否 可正常切换Java 版
  • 软件测试从自学到工作,软件测试学习到底要怎样进行?

    前言 首先 请不要奢望有多么简单的办法 学习没有捷径 这里只是让你明白这一点 顺便根据个人经验帮你理一下学习的过程 其实有文章是说怎么学习以及学习什么的 但是可能还是有些抽象 或者内容有点多 有点杂 以至于不少朋友仍然觉得不知道如何下手 大
  • R语言描述性统计

    使用Hmisc这个包 只需要调用 my data read csv test csv Hmisc describe my data 可以打印出各个变量的均值方差等信息
  • mysql远程连接权限grant all privileges on *.* to ‘root‘@‘%‘ identified by ‘123456‘ with grant option语句报错

    mysql远程连接权限grant all privileges on to root identified by 123456 with grant option语句报错 记录一下自己安装mysql遇到的小坑 grant all privi
  • Integer中缓存池讲解

    文章目录 一 简介 二 实现原理 三 修改缓存范围 一 简介 Integer缓存池是一种优化技术 用于提高整数对象的重用和性能 在Java中 对于整数值在 128 到 127 之间的整数对象 会被放入缓存池中 以便重复使用 这是因为在这个范
  • Centos7操作系统服务器优化流程(关闭防火墙、关闭selinux、更换yum源、安装Docker和docker-compose)

    Centos7 测试环境服务器优化流程 本文讲解内容 将Centos7操作系统作为公司开发环境或者自学者搭建DevOps流程而优化的几项内容 生产环境慎用 防止被网络攻击 纯干货教程 已在本地操作多次 请放心使用 推荐一个笔者长期使用的ss
  • 卡西欧casio手表质量怎么样

    Casio的仿货 淘宝在300以上的质量都还可以 500以上手感就挺好了 我买了一个4折的 没问题 绝对真货 有真货单的 带激光防伪标 好像是广东出的 就是没发票 不过店家保一年 但我觉得casio的质量还是可以的 一年内不会有问题 1年后
  • Jupyter 配置默认工作目录(起始位置)

    没有配置文件 1 安装了 Anaconda 在Anaconda prompt中输入以下命令 也可以用来查找已有配置文件路径 jupyter lab jupyter lab generate config jupyter notebook j
  • OVP保护芯片首选ETA7008,耐压36V,过压保护点可调

    产品描述主要特点 低成本 过压保护点可调 高耐压 低内阻 快速响应ETA7008是一款低侧过压保护 OVP IC 仅具有34mohm开关电阻 确保非常低的导通电阻和高保护电压 负端保护 耐压36V 过压保护点可设 导通内阻小 可蕞大过4A电
  • clang-format configurator - 交互式创建 clang-format 格式配置文件

    clang format configurator 交互式创建 clang format 格式配置文件 clang format configurator https zed0 co uk clang format configurator
  • Apache APISIX 默认密钥漏洞(CVE-2020-13945)

    Vulhub Apache APISIX 默认密钥漏洞 CVE 2020 13945 文章目录 Vulhub Apache APISIX 默认密钥漏洞 CVE 2020 13945 APISIX简介 漏洞复现 payload分析 APISI
  • PCB板框文件丢失的问题

    问题 PCB 板框文件丢失的问题 在制作好PCB并导出Gerber文件后 送厂制板的时候审查被提醒说没有边框文件 缺少 GM1 层 解决办法 经过反复检查 确定添加了边框文件 BOARD GEOMETRY CUT Design outlin
  • Spark Job写文件个数的控制以及小文件合并的一个优化

    文章目录 背景说明 通过引入额外Shuffle对写入数据进行合并 EnsureRepartitionForWriting Rule CoalesceShufflePartitions Rule OptimizeShuffleWithLoca
  • xdoj单词排序

    标题 单词排序 描述 定义一个二维字符数组str 10 20 行号表示单词序号 列号表示单词最大长度 输入一个正整数N N 10 表示单词数 使用函数wd sort 完成单词的排序 按字母顺序从小到大排列单词 使用指针完成地址传递 主函数完
  • 常用加密解密算法【RSA、AES、DES、MD5】介绍和使用

    为了防止我们的数据泄露 我们往往会对数据进行加密 特别是敏感数据 我们要求的安全性更高 下面将介绍几种常用的加密算法使用 这些算法的加密对象都是基于二进制数据 如果要加密字符串就使用统一编码 如 utf8 进行编码后加密 1 摘要算法 常用