【问题标题】:What does update method of MessageDigest do and what is BASE64Encoder meant for?MessageDigest 的更新方法是做什么的,BASE64Encoder 的用途是什么?
【发布时间】:2019-06-11 03:35:52
【问题描述】:

以下是加密用户字符串的代码:

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import sun.misc.BASE64Encoder;
import java.io.*;

class Encrypter {
public synchronized String encrypt(String plainText) throws Exception {
    MessageDigest md = null;
    try {
        md = MessageDigest.getInstance("SHA");
    }catch(Exception exc) {
        throw new Exception(exc.getMessage());
     }

     try {
        md.update(plainText.getBytes("UTF-8"));
     }catch(Exception exc) {
        throw new Exception(exc.getMessage());
      }

      byte raw[] = md.digest();
      String hash = (new BASE64Encoder()).encode(raw);
      return hash;
}
public static void main(String args[]) {
    try {
        Encrypter encrypter = new Encrypter();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String userInput = br.readLine();
        String encryptedPassword = encrypter.encrypt(userInput);
        System.out.println(encryptedPassword);
    } catch(Exception exc) {
        System.out.println(exc);
      }
}
}

当我编译代码时,我得到了这些警告:

Encrypter.java:4: warning: BASE64Encoder is internal proprietary API and may be removed in a future release
import sun.misc.BASE64Encoder;
           ^
Encrypter.java:23: warning: BASE64Encoder is internal proprietary API and may be removed in a future release
              String hash = (new BASE64Encoder()).encode(raw);
                                 ^
2 warnings

还有其他方法可以在java中加密字符串吗?

MessageDigest 类的方法update 有什么作用?即md.update(plainText.getBytes("UTF-8")); 的声明是做什么的?

什么是BASE64Encoder 类?我找不到它的 DOC

【问题讨论】:

标签: java encryption cryptography


【解决方案1】:
  1. 首先,您没有执行任何加密。您正在计算输入的单向哈希或摘要。这个散列可以稍后用于验证消息的完整性。请参阅HashingSHA1MessageDigest

  2. Base64 encoding 是一种用 ASCII 表示二进制数据的方法。这通常是可取的,因为并非所有数据存储和传输机制都支持原始二进制文件。例如,如果您想通过 http 查询字符串参数传输计算的摘要,您需要将其编码为 Base64。此外,将原始二进制文件保存或打印到控制台会产生一系列时髦字符,这些字符可能超出可打印范围,并且还可能从您的 PC 扬声器中发出哔哔声!

  3. 您使用的Base64Encoder 来自sun.misc 包,永远不要使用。这是内部的 Sun JVM 代码,将来可能会也可能不会。这也解释了为什么您找不到任何 javadoc。

  4. 幸运的是,存在一些免费和开放的 Base64 编码器和解码器。 Apache Commons Codec 是一个广泛使用且稳定的库,其中包含多个编解码器,包括 Base64

  5. md.update(plainText.getBytes("UTF-8")) 更新摘要的输入。调用digest 执行最终更新并计算输入的摘要。请参阅 md.digestmd.update 的 javadoc

【讨论】:

  • 所以 ``md.digest` 返回二进制值数组?
  • 是的,md.digest 返回一个带有二进制原始摘要的byte []
  • 是的,但是在您的第 5 号中,“将输入更新为摘要”到底是什么意思?它会将新字节连接到当前摘要或原始输入吗?
【解决方案2】:
【解决方案3】:

虽然这里的旧帖子是更新的答案。 Java 8 的 Base64。

Java 8 Base64 Documents

【讨论】:

    【解决方案4】:

    对于 Base64 加密和解密,此警告明确表示不鼓励使用 Sun 的 Base64Encoder 实现,并警告该实现可能在未来的版本中被删除,我们可以做的是切换到 Base64 的其他实现编码器。我们可以将Commons Codec library 用于 Base64 编码器。下面是一个例子:

    1. Add Commons Codec library in classpath of your project
    2. Add import statement for Base64 Class.
    
    import org.apache.commons.codec.binary.Base64;
    
    3. Encrypt your data
    
    String testString = "Hello World";
    byte[] encodedBytes = Base64.encodeBase64(testString.getBytes());
    // Get encoded string
    String encodedString = new String(encodedBytes);
    // Get decoded string back
    String decodedString = new String(Base64.decodeBase64(encodedBytes));
    

    使用 Commons 编解码器库后,您应该不会再看到上述警告。

    【讨论】:

      【解决方案5】:

      为了构建 bullet 5 from Sahil Muthoo's excellent answer,下面是对源代码的更深入了解。

      默认情况下,update 方法只是将输入字节数组附加到MessageDigestSpi 抽象类的当前tempArray

      MessageDigest 类扩展了 MessageDigestSpi 类。然后MessageDigest.update被调用,方法MessageDigestSpi.engineUpdate被调用,查源码可以发现:

      MessageDigest.java (source code)

      196:   /**
      197:    * Updates the digest with the byte.
      ...
      200:    */
      201:   public void update(byte input)
      202:   {
      203:     engineUpdate(input);
      204:   }
      205: 
      206:   /**
      207:    * Updates the digest with the bytes from the array starting from the
      208:    * specified offset and using the specified length of bytes.
      209:    * 
      210:    * @param input
      211:    *          bytes to update the digest with.
      212:    * @param offset
      213:    *          the offset to start at.
      214:    * @param len
      215:    *          length of the data to update with.
      216:    */
      217:   public void update(byte[] input, int offset, int len)
      218:   {
      219:     engineUpdate(input, offset, len);
      220:   }
      ...
      227:   public void update(byte[] input)
      228:   {
      229:     engineUpdate(input, 0, input.length);
      230:   }
      ...
      238:   public void update (ByteBuffer input)
      239:   {
      240:     engineUpdate (input);
      241:   }
      

      MessageDigestSpi.engineUpdate 是一个抽象方法,必须通过扩展类来实现,如下所示:

      MessageDigestSpi.java (source code)

      42:    /**
      43:     * Updates this {@code MessageDigestSpi} using the given {@code byte}.
      44:     *
      45:     * @param input
      46:     *            the {@code byte} to update this {@code MessageDigestSpi} with.
      47:     * @see #engineReset()
      48:     */
      49:    protected abstract void engineUpdate(byte input);
      50:    /**
      51:     * Updates this {@code MessageDigestSpi} using the given {@code byte[]}.
      52:     *
      53:     * @param input
      54:     *            the {@code byte} array.
      55:     * @param offset
      56:     *            the index of the first byte in {@code input} to update from.
      57:     * @param len
      58:     *            the number of bytes in {@code input} to update from.
      59:     * @throws IllegalArgumentException
      60:     *             if {@code offset} or {@code len} are not valid in respect to
      61:     *             {@code input}.
      62:     */
      63:    protected abstract void engineUpdate(byte[] input, int offset, int len);
      64:    /**
      65:     * Updates this {@code MessageDigestSpi} using the given {@code input}.
      66:     *
      67:     * @param input
      68:     *            the {@code ByteBuffer}.
      69:     */
      70:    protected void engineUpdate(ByteBuffer input) {
      71:        if (!input.hasRemaining()) {
      72:            return;
      73:        }
      74:        byte[] tmp;
      75:        if (input.hasArray()) {
      76:            tmp = input.array();
      77:            int offset = input.arrayOffset();
      78:            int position = input.position();
      79:            int limit = input.limit();
      80:            engineUpdate(tmp, offset+position, limit - position);
      81:            input.position(limit);
      82:        } else {
      83:            tmp = new byte[input.limit() - input.position()];
      84:            input.get(tmp);
      85:            engineUpdate(tmp, 0, tmp.length);
      86:        }
      87:    }
      

      【讨论】:

        猜你喜欢
        • 2018-04-24
        • 2022-01-31
        • 1970-01-01
        • 2016-10-24
        • 2021-06-04
        • 2010-09-27
        • 2011-12-17
        • 2010-11-21
        相关资源
        最近更新 更多