MD5 code and related derivatives


@MD5 code and related derivatives

When writing the Yimainet project, I was asked to encrypt the user password, check the information online, and take notes again. The code was not written by myself, but I just integrated the records I needed to read and learn. I am grateful


**

1. JAVA package java.security is the encryption API provided by java-MessageDigest

**

  1. Function: Provide encryption algorithms such as MD5, SHA-1, SHA-256. It can accept input of any length and produce output of fixed length. The output can generally be called a digest or hash
  2. We can generally use MessageDigest for some conventional encryption operations, the specific usage is as follows:
//实例化一个MessageDigest对象,通过提供的静态的getInstance方法。方法中参数指的是加密的算法,大小写无所谓。
MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
//输入待加密的字符串
messageDigest.update("待加密的字符串");
//加密之后生成的密文的字节数组
byte[] value = messageDigest.digest();
//一般不会直接使用生成的字节数组,而是转化成16进行字符串,长度一般可以设定


//下来将提供字节数组转化为16进制字符串的方法``
/**
 * 字符串数组解析成16进制字符串
 *  md : 待转化的字节数组
 * needLen: 需要转化的16进制字符串的长度,一般都是偶数
 * 说明:此算法可以设定生成的16进制字符串的长度,是拿原字节数组的前needLen/2长度的字节数组转化而来的
 *       如果不需要特定长度,直接全部转,可以设置needLen的长度为md.length*2,获取去掉needLen,设定buf的长度为j*2,for循环的      
 *       终止条件为i<j*2 即可
 * */
private static String tranform16Str(byte[] md, int needLen){
    
    
    char[] hexDigits = {
    
    '0','1','2','3','4','5','6','7','8','9',
            'a','b','c','d','e','f'};
    try {
    
    
        int j = md.length;
        char buf[] = new char[needLen];
        int k = 0;
        for (int i = 0; i < needLen/2; i++) {
    
    
            byte byte0 = md[i];
            buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
            buf[k++] = hexDigits[byte0 & 0xf];
        }
        return new String(buf);
    } catch (Exception e) {
    
    
        log.error("加密后的密文转化为16进制字符串过程中出现异常,",e);
    }
    return null;
}

Simple example:

/*MySQL*/
//为了避免用户密码直接裸露存储在数据库中,应对用户密码进行加密,有些数据库就有加密函数,比如oracle,有个示例如下,进行对密码字段加密: 
CREATE   OR   REPLACE   function   md5(input_string   VARCHAR2)   return   varchar2   
  IS   
  raw_input   RAW(128)   :=   UTL_RAW.CAST_TO_RAW(input_string);   
  decrypted_raw   RAW(2048);   
  error_in_input_buffer_length   EXCEPTION;   
  BEGIN   
  --dbms_output.put_line(sysdate   ||   '>   加密前的数据:'   ||   input_string);   
  sys.dbms_obfuscation_toolkit.MD5(input   =>   raw_input,   
  checksum   =>   decrypted_raw);   
  --dbms_output.put_line(sysdate   ||   '>   加密后的数据:'   ||   rawtohex(decrypted_raw));   
  return   lower(rawtohex(decrypted_raw));   
  END; 

And this method also has its flaws and is only suitable for a specific database. Once the database is changed (not all databases have encryption and decryption storage functions), this encryption method cannot be used.
What I want to discuss here is to use java method to encrypt data with MD5 code, which is relatively simple, because java has ready-made classes java.security, MessageDigest to help us generate MD5 codes.
The idea is to convert the password characters to MD5 codes and store them in the database. When the user logs in, the password characters entered in the login are converted to MD5 codes, and then compared with the password MD5 codes stored in the database; if the user changes the password, Replace the MD5 code of the new password.
The function to generate MD5 code is as follows:

  /** 
     * 把字符窜转化成MD5码,主要针对密码 
     * @param str 待转码的字符窜 
     * @return MD5码字符窜 
     * @author Tony Lin Added on 2008-9-27 
     */ 
    public String getMD5String(String str){
    
     
     try{
    
     
      byte psw[] = str.getBytes(); 
      MessageDigest md = MessageDigest.getInstance("MD5"); 
      md.update(psw); 
      return this.toHex(md.digest()); 
       
     } catch (IllegalStateException e) {
    
     
            return null; 
        } catch (NoSuchAlgorithmException e) {
    
     
            return null; 
        } 
    } 
     
    /** 
     * 把byte型数组类容拼错成字符窜 
     * @param buffer The byte array to be converted 
     * @return String 
     * @author Tony Lin Added on 2008-9-27 
     */ 
    public String toHex(byte buffer[]) {
    
     
        StringBuffer sb = new StringBuffer(); 
        String s = null; 
        for (int i = 0; i < buffer.length; i++) {
    
     
            s = Integer.toHexString((int) buffer[i] & 0xff); 
            if (s.length() < 2) {
    
     
                sb.append('0'); 
            } 
            sb.append(s); 
        } 
        return sb.toString(); 
    }

The original
above

derivative

  • Continue (1) the first point

What to do if you encrypt a file. How to encrypt a file that is so long?

//上面有这么一句
messageDigest.update("待加密的字符串");
/*从上面的注释上看,这个是添加待加密的明文的。
那么如果需要给一个文件进行加密怎么办。文件那么长又该如何加密?*/
//1.首先先把文件读取到一个字节数组里面
File file = new File(filePath);
InputStream in = new FileInputStream(file);
byte[] allData = readInputStream(in);//获取到文件的内容

/*接下来需要给这些内容进行加密,就需要使用到上面的MessageDigest加密的Api了。
有两种方式:*/
//方式1:一段一段往里面塞

int len = allData.length;
int i = 0;
while(true){
    
    
    try{
    
    
        int arrLen = (len - i * 4096) > 4096 ? 4096 : (len - i * 4096);
        byte[] content = new byte[arrLen];
        System.arraycopy(getData, i * 4096, content, 0, arrLen);
        messageDigest.update(content);
        i++;
    }catch (Exception e){
    
    
        log.info("字节数组拷贝出现异常,表示完成 i ={}", i);
        break;
    }
}
byte[] transform = messageDigest.digest();
//说明,MessageDigest调用digest()方法之后  输入的摘要将被重置,意思就是之后需要再加密的话  可以直接使用之前已有的对象
String miwen = tranform16Str(transform, transform.length);

//方式2:一次性全部往里面塞
messageDigest.update(allData);
byte[] second = messageDigest.digest();
//之后再进行16进制的转换操作。

#####################################################################
/*上述两种方法的结果拿到的是一样的。
那么就说明多次的update操作  只是单纯的摘要内容的追加操作。*/
/**
* 获取输入流中的内容到字节数组里面
**/
public static byte[] readInputStream(InputStream inputStream) throws IOException {
    
    
    byte[] buffer = new byte[1024];
    int len = 0;
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    while ((len = inputStream.read(buffer)) != -1) {
    
    
        bos.write(buffer, 0, len);
    }
    bos.close();
    return bos.toByteArray();
}

buffer[i] & 0xff

When encrypting in the code, bytes[i] & 0xFF are used

MessageDigest md5 = MessageDigest.getInstance(“MD5”);

        bytes = md5.digest(basestring.toString().getBytes("UTF-8"));

String hex = Integer.toHexString(bytes[i] & 0xFF);

First you have to be clear about a few concepts

1.byte的取值范围

    byte java 中一个字节 8位 即 -2^7—2^7-1  范围是 -128——127 (*对这个有疑问吗?在2 中解答)

 2.计算机中负数的存储的值是它的补码

   补码计算方法  负数取值是它的绝对值,的二进制数,取反,加1,那么对于          -128——-1的存储 就知道了吧

            举个例子 -12   绝对值------> 12  就是   0000  1100  取反------> 1111 0011 加 1  1111 0100 (晓得不)

    那么-128——127  就可以理解了

      -128  是    绝对值 128  二进制-------->  1000 0000   取反  0111 1111(127)  加1  ,1000 0000 (128)

      -1 的绝对值 是  1   0000 0001  取反  1111 1110 加1   1111 1111 (255) 

     计算机 中   -128——-1 对应存储的是   128-255  

      再看 2^7-1  也就是127 刚好 是0111 1111  为啥减1  因为 128 已经被占了 所以  

   -128——127  在数据库中真实存的是   128——255  外加  0——127   也就是 byte真正在计算机中存储范围是 

          0——255 只不过我们说的是它的取值范围  是 -128——127

 3.byte 转 int 16进制 (int  -2^31——2^31-1)

  bytes[i] & 0xFF

          byte和int运算,计算机会自动将 byte转化为32位,然后再运算,也就是8位转32位,那么计算机会自动将高位补1

          所以-12 在计算机种就是    1111 0011--------> 1111 1111 1111 1111 1111 1111 1111 0100

然后 &  0xFF     

         0x 代表16进制   每一位取值范围是  0 —— 15 

          但是 10——15之间是两位数字了,会和10进制分部开 所以 10——15就对应了 A——F

         那么0xFF 就是   0000 0000 0000 0000 0000 0000 1111 1111 

         &运算  得到 0000 0000 0000 0000  0000 0000  1111 0100

Did you find anything? The lower eight bits 1111 0011 have not changed, so why & 0xFF instead of anything else?

The reason is that the first 24 bits of byte to int are forced to be 1 by the computer, 1111 1111 1111 1111 1111 1111 1111 1111 0100 is not converted to int

-12 is the value stored in the computer, & 0xFF 0000 0000 0000 0000 0000 0000 1111 1111 exactly the first 24 bits are all 0, and the & operation will only keep

The lower eight bits are the value 1111 0100 originally stored in the computer in the byte.

Above original

integer.tohexstring

Integer.toHexString this method is to display bytes (converted to int) in hexadecimal format.
Related notes from others

Bit operator

Bit operator

  • Six bitwise operators in C language:
  • "&" bitwise and
  • "|" bitwise or
  • "^" bitwise XOR
  • "~" reverse
  • "<<" move left
  • ">>" move right

Because of the content of the project, I mainly only recorded &: bitwise and
bitwise AND operator "&" is a binocular operator. Its function is the binary phase AND corresponding to the two numbers involved in the operation. Only when the corresponding two binary bits are both 1, the result bit is 1, otherwise it is 0. The number involved in the operation appears in the form of complement.

For example: 9&5 can be written as follows: 00001001 (9's two's complement) &00000101 (5's two's complement) 00000001 (1's two's complement) See 9&5=1. The bitwise AND operation is usually used to clear certain bits or reserve certain bits. For example, clear the high eight bits of a to 0, and reserve the low eight bits for a&255 operation (the binary number of 255 is 11111111).


Convert decimal to binary

Base conversion

Converting a decimal integer to a binary integer The conversion of a decimal integer to a binary integer adopts the method of "divide by 2 and take the remainder, arrange in reverse order". The specific method is: Divide the decimal integer by 2 to get a quotient and remainder; then divide the quotient with 2 to get a quotient and remainder. Continue this way until the quotient is less than 1, and then use the first obtained remainder as binary The low-significant digits of the number, and the remainder obtained as the high-significant digits of the binary number, are arranged in sequence.

Convert decimal integer to binary,
such as:
255=(11111111)B
255/2=127=Remaining 1
127/2=63
Remaining 1
63/2=31
=Remaining 1
31/2=15
=Remaining 1
15/2=7
Remaining 1
7/2=3
=Remaining 1
3/2=1
=Remainder 1
1/2=0
=== more than 1


I found that the binary 00001001 of the above "9" (9's two's complement) is different from the binary 1001 that I calculated according to the algorithm, so what is the number of "0"s in the kilometer

Two's complement (two's complement)

There are three ways to represent the signed number in the computer, namely the original code, the inverse code and the complement code. The three representation methods have two parts: the sign bit and the value bit. The sign bit uses 0 to indicate "positive" and 1 to indicate "negative", while the value bit has different representation methods. In computer systems, values ​​are always represented and stored in complements. The reason is that by using the complement code, the sign bit and the value field can be processed uniformly; at the same time, addition and subtraction can also be processed uniformly.

So the previous "1001" is the value bit, therefore, the previous string of "0" is the sign bit


Before introducing the concept of complement code, let me introduce the concept of "modulus": "modulus" refers to the counting range of a metering system, such as the bucket and clock used to measure grain in the past. A computer can also be regarded as a metering machine, because the word length of a computer is fixed, that is, the number of bits stored and processed is limited, so it also has a metering range, that is, there is a "modulus". For example: the measuring range of the clock is 0~11, modulo=12. The computer measurement range of n bits is, modulo =. "Module" is essentially the amount of "overflow" produced by the meter. Its value cannot be expressed on the meter, and the meter can only show the remainder of the modulus. Any meter with a modulus can transform subtraction into addition.
It is to add 1 after the inversion.
Assuming that the current hour hand points to 8 o'clock and the exact time is 6 o'clock, there are two ways to adjust the time: one is to dial 2 hours backward, that is, 8-2=6; the other is to dial 10 hours forward, 8+ 10=12+6=6, that is, 8-2=8+10=8+12-2 (mod 12). In a system where 12 is a modulus, the effect of adding 10 and subtracting 2 is the same, so any subtraction operation can be replaced by adding 10. If the general formula is used, it can be expressed as: ab=a-b+mod=a+mod-b. For "modulus", 2 and 10 are complementary numbers. In fact, in the system with 12 as the modulus, 11 and 1, 8 and 4, 9 and 3, 7 and 5, 6 and 6 have this characteristic, and the common characteristic is that the sum of the two is equal to the modulus. For computers, the concepts and methods are exactly the same. For an n-bit computer, if n=8, the maximum number that can be represented is 11111111. If you add 1 to 100000000 (9 bits), because there are only 8 bits, the highest bit 1 is naturally lost. It returns to 00000000, so the modulus of the 8-bit binary system is. In such a system, the subtraction problem can also be transformed into an addition problem, just use the corresponding complement to express the subtraction. The complement is used in the processing of computer logarithms, which is the complement.

Example: The complement of +9 is 00001001. (Remarks: This +9's complement is expressed in 8-bit binary, and there are many ways to express it. There are also 16-bit two's complement representation, and 32-bit two's complement representation, 64-bit complement Code representation, etc. Each complement representation can only represent a limited number of numbers.)


Guess you like

Origin blog.csdn.net/MarKie_forJAVA/article/details/108770570