[转帖]Java 加密解密之消息摘要算法(MD5 SHA MAC)_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3818 | 回复: 0   主题: [转帖]Java 加密解密之消息摘要算法(MD5 SHA MAC)        下一篇 
Leon
注册用户
等级:少校
经验:1436
发帖:116
精华:7
注册:2013-1-4
状态:离线
发送短消息息给Leon 加好友    发送短消息息给Leon 发消息
发表于: IP:您无权察看 2013-1-8 10:05:27 | [全部帖] [楼主帖] 楼主

Java 加密解密之消息摘要算法(MD5 SHA MAC)

消息摘要

消 息摘要(Message Digest)又称为数字摘要(Digital Digest)。它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通 过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。消息摘要采用单向Hash 函数将需加密 的明文"摘要"成一串128bit的密文,这一串密文亦称为数字指纹(Finger Print),它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致 。这样这串摘要便可成为验证明文是否是"真身"的"指纹"了。

HASH函数的抗冲突性使得如果一段明文稍有变化,哪怕只更改该段落的一个字母,通过哈希算法作用后都将产生不同的值。而HASH算法的单向性使得要找到到哈希值相同的两个不 同的输入消息,在计算上是不可能的。所以数据的哈希值,即消息摘要,可以检验数据的完整性。哈希函数的这种对不同的输入能够生成不同的值的特性使得无法找到两个具有相同哈希值的输入。因此,如果两个文档经哈希转换后成为相同的值,就可以肯定它们是同一文档。
所以,当希望有效地比较两个数据块时,就可以比较它们的哈希值。例如,可以通过比较邮件发送前和发送后的哈希值来验证该邮件在传递时是否修改。 

消息摘要算法

消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。消息摘要算法不存在 密钥的管理与分发问题,适合于分布式网络相同上使用。由于其加密计算的工作量相当可观,所以以前的这种算法通常只用于数据量有限的情况下的加密,例如计算机的口令就是 用不可逆加密算法加密的。近年来,随着计算机相同性能的飞速改善,加密速度不再成为限制这种加密技术发展的桎梏,因而消息摘要算法应用的领域不断增加。

消息摘要算法的特点:

① 无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。
② 消息摘要看起来是“随机的”。这些比特看上去是胡乱的杂凑在一起的。
③ 一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。
④ 消息摘要函数是无陷门的单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。
⑤ 好的摘要算法,无法找到两条消息,是它们的摘要相同。

现有的消息摘要算法

消息摘要算法包含MD、SHA和MAC三大系列,常用于验证数据的完整性,是数据签名算法的核心算法。 
MAC与MD和SHA不同,MAC是含有密钥的散列函数算法,我们也常把MAC称为HMAC。


JDK对消息摘要算法的支持

JDK6支持MD2/MD5/SHA/SHA256/SHA384/SHA512/HmacMD5/HmacSHA1/ HmacSHA256/HmacSHA384/HmacSHA512


使用到十六进制工具类Hex.java  见:  java byte数组与十六进制字符串互转

MD和SHA系列的java实现:

DigestUtils.java


Java代码:

  1. import java.security.MessageDigest; 
  2. import java.security.NoSuchAlgorithmException; 
  3. /** 
  4.  * reference apache commons <a 
  5.  * href="http://commons.apache.org/codec/">http://commons.apache.org/codec/</a> 
  6.  * 
  7.  * support MD2/MD5/SHA/SHA256/SHA384/SHA512 
  8.  * @author Aub 
  9.  * 
  10.  */ 
  11. public class DigestUtils { 
  12.  
  13.  /** 
  14.  * 根据给定摘要算法创建一个消息摘要实例 
  15.  * 
  16.  * @param algorithm 
  17.  * 摘要算法名 
  18.  * @return 消息摘要实例 
  19.  * @see MessageDigest#getInstance(String) 
  20.  * @throws RuntimeException 
  21.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  22.  */ 
  23.  static MessageDigest getDigest(String algorithm) { 
  24.  try { 
  25.  return MessageDigest.getInstance(algorithm); 
  26.  } catch (NoSuchAlgorithmException e) { 
  27.  throw new RuntimeException(e.getMessage()); 
  28.  } 
  29.  } 
  30.  
  31.  /** 
  32.  * 获取 MD5 消息摘要实例 
  33.  * 
  34.  * @return MD5 消息摘要实例 
  35.  * @throws RuntimeException 
  36.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  37.  */ 
  38.  private static MessageDigest getMd5Digest() { 
  39.  return getDigest("MD5"); 
  40.  } 
  41.  
  42.  /** 
  43.  * 获取 SHA-1 消息摘要实例 
  44.  * 
  45.  * @return SHA-1 消息摘要实例 
  46.  * @throws RuntimeException 
  47.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  48.  */ 
  49.  private static MessageDigest getShaDigest() { 
  50.  return getDigest("SHA"); 
  51.  } 
  52.  
  53.  /** 
  54.  * 获取 SHA-256 消息摘要实例 
  55.  * 
  56.  * @return SHA-256 消息摘要实例 
  57.  * @throws RuntimeException 
  58.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  59.  */ 
  60.  private static MessageDigest getSha256Digest() { 
  61.  return getDigest("SHA-256"); 
  62.  } 
  63.  
  64.  /** 
  65.  * 获取 SHA-384 消息摘要实例 
  66.  * 
  67.  * @return SHA-384 消息摘要实例 
  68.  * @throws RuntimeException 
  69.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  70.  */ 
  71.  private static MessageDigest getSha384Digest() { 
  72.  return getDigest("SHA-384"); 
  73.  } 
  74.  
  75.  /** 
  76.  * 获取 SHA-512 消息摘要实例 
  77.  * 
  78.  * @return SHA-512 消息摘要实例 
  79.  * @throws RuntimeException 
  80.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  81.  */ 
  82.  private static MessageDigest getSha512Digest() { 
  83.  return getDigest("SHA-512"); 
  84.  } 
  85.  
  86.  /** 
  87.  * 使用MD5消息摘要算法计算消息摘要 
  88.  * 
  89.  * @param data 
  90.  * 做消息摘要的数据 
  91.  * @return 消息摘要(长度为16的字节数组) 
  92.  */ 
  93.  public static byte[] encodeMD5(byte[] data) { 
  94.  return getMd5Digest().digest(data); 
  95.  } 
  96.  
  97.  /** 
  98.  * 使用MD5消息摘要算法计算消息摘要 
  99.  * 
  100.  * @param data 
  101.  * 做消息摘要的数据 
  102.  * @return 消息摘要(长度为32的十六进制字符串) 
  103.  */ 
  104.  public static String encodeMD5Hex(byte[] data) { 
  105.  return Hex.encodeHexStr(encodeMD5(data)); 
  106.  } 
  107.  
  108.  /** 
  109.  * 使用SHA-1消息摘要算法计算消息摘要 
  110.  * 
  111.  * @param data 
  112.  * 做消息摘要的数据 
  113.  * @return SHA-1消息摘要(长度为20的字节数组) 
  114.  */ 
  115.  public static byte[] encodeSHA(byte[] data) { 
  116.  return getShaDigest().digest(data); 
  117.  } 
  118.  
  119.  /** 
  120.  * 使用SHA-1消息摘要算法计算消息摘要 
  121.  * 
  122.  * @param data 
  123.  * 做消息摘要的数据 
  124.  * @return SHA-1消息摘要(长度为40的十六进制字符串) 
  125.  */ 
  126.  public static String encodeSHAHex(byte[] data) { 
  127.  return Hex.encodeHexStr(getShaDigest().digest(data)); 
  128.  } 
  129.  
  130.  /** 
  131.  * 使用SHA-256消息摘要算法计算消息摘要 
  132.  * 
  133.  * @param data 
  134.  * 做消息摘要的数据 
  135.  * @return SHA-256消息摘要(长度为32的字节数组) 
  136.  */ 
  137.  public static byte[] encodeSHA256(byte[] data) { 
  138.  return getSha256Digest().digest(data); 
  139.  } 
  140.  
  141.  /** 
  142.  * 使用SHA-256消息摘要算法计算消息摘要 
  143.  * 
  144.  * @param data 
  145.  * 做消息摘要的数据 
  146.  * @return SHA-256消息摘要(长度为64的十六进制字符串) 
  147.  */ 
  148.  public static String encodeSHA256Hex(byte[] data) { 
  149.  return Hex.encodeHexStr(encodeSHA256(data)); 
  150.  } 
  151.  
  152.  /** 
  153.  * 使用SHA-384消息摘要算法计算消息摘要 
  154.  * 
  155.  * @param data 
  156.  * 做消息摘要的数据 
  157.  * @return SHA-384消息摘要(长度为43的字节数组) 
  158.  */ 
  159.  public static byte[] encodeSHA384(byte[] data) { 
  160.  return getSha384Digest().digest(data); 
  161.  } 
  162.  
  163.  /** 
  164.  * 使用SHA-384消息摘要算法计算消息摘要 
  165.  * 
  166.  * @param data 
  167.  * 做消息摘要的数据 
  168.  * @return SHA-384消息摘要(长度为86的十六进制字符串) 
  169.  */ 
  170.  public static String encodeSHA384Hex(byte[] data) { 
  171.  return Hex.encodeHexStr(encodeSHA384(data)); 
  172.  } 
  173.  
  174.  /** 
  175.  * 使用SHA-512消息摘要算法计算消息摘要 
  176.  * 
  177.  * @param data 
  178.  * 做消息摘要的数据 
  179.  * @return SHA-512消息摘要(长度为64的字节数组) 
  180.  */ 
  181.  public static byte[] encodeSHA512(byte[] data) { 
  182.  return getSha512Digest().digest(data); 
  183.  } 
  184.  
  185.  /** 
  186.  * 使用SHA-512消息摘要算法计算消息摘要 
  187.  * 
  188.  * @param data 
  189.  * 做消息摘要的数据 
  190.  * @return SHA-512消息摘要(长度为128的十六进制字符串) 
  191.  */ 
  192.  public static String encodeSHA512Hex(byte[] data) { 
  193.  return Hex.encodeHexStr(encodeSHA512(data)); 
  194.  } 
  195.  


参考 org.apache.commons.codec.digest.DigestUtils
下载地址:http://commons.apache.org/codec/download_codec.cgi

MAC系列的java实现

Hmac.java


Java代码:

  1. import java.security.InvalidKeyException; 
  2. import java.security.Key; 
  3. import java.security.NoSuchAlgorithmException; 
  4. import javax.crypto.KeyGenerator; 
  5. import javax.crypto.Mac; 
  6. import javax.crypto.SecretKey; 
  7. import javax.crypto.spec.SecretKeySpec; 
  8. /** 
  9.  * Hmac<br/> 
  10.  * algorithm HmacMD5/HmacSHA/HmacSHA256/HmacSHA384/HmacSHA512 
  11.  * @author Aub 
  12.  */ 
  13. public class Hmac { 
  14.  
  15.  /** 
  16.  * 根据给定密钥生成算法创建密钥 
  17.  * 
  18.  * @param algorithm 
  19.  * 密钥算法 
  20.  * @return 密钥 
  21.  * @throws RuntimeException 
  22.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  23.  */ 
  24.  private static byte[] getHmacKey(String algorithm){ 
  25.  //初始化KeyGenerator 
  26.  KeyGenerator keyGenerator = null; 
  27.  try { 
  28.  keyGenerator = KeyGenerator.getInstance(algorithm); 
  29.  } catch (NoSuchAlgorithmException e) { 
  30.  throw new RuntimeException(e.getMessage()); 
  31.  } 
  32.  //产生密钥 
  33.  SecretKey secretKey = keyGenerator.generateKey(); 
  34.  //获得密钥 
  35.  return secretKey.getEncoded(); 
  36.  } 
  37.  
  38.  /** 
  39.  * 获取 HmaMD5的密钥 
  40.  * 
  41.  * @return HmaMD5的密钥 
  42.  * @throws RuntimeException 
  43.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  44.  */ 
  45.  public static byte[] getHmaMD5key(){ 
  46.  return getHmacKey("HmacMD5"); 
  47.  } 
  48.  
  49.  /** 
  50.  * 获取 HmaSHA的密钥 
  51.  * 
  52.  * @return HmaSHA的密钥 
  53.  * @throws RuntimeException 
  54.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  55.  */ 
  56.  public static byte[] getHmaSHAkey(){ 
  57.  return getHmacKey("HmacSHA1"); 
  58.  } 
  59.  
  60.  /** 
  61.  * 获取 HmaSHA256的密钥 
  62.  * 
  63.  * @return HmaSHA256的密钥 
  64.  * @throws RuntimeException 
  65.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  66.  */ 
  67.  public static byte[] getHmaSHA256key(){ 
  68.  return getHmacKey("HmacSHA256"); 
  69.  } 
  70.  
  71.  /** 
  72.  * 获取 HmaSHA384的密钥 
  73.  * 
  74.  * @return HmaSHA384的密钥 
  75.  * @throws RuntimeException 
  76.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  77.  */ 
  78.  public static byte[] getHmaSHA384key(){ 
  79.  return getHmacKey("HmacSHA384"); 
  80.  } 
  81.  
  82.  /** 
  83.  * 获取 HmaSHA512的密钥 
  84.  * 
  85.  * @return HmaSHA384的密钥 
  86.  * @throws RuntimeException 
  87.  * 当 {@link java.security.NoSuchAlgorithmException} 发生时 
  88.  */ 
  89.  public static byte[] getHmaSHA512key(){ 
  90.  return getHmacKey("HmacSHA512"); 
  91.  } 
  92.  
  93.  /** 
  94.  * 转换密钥 
  95.  * 
  96.  * @param key 二进制密钥 
  97.  * @param algorithm 密钥算法 
  98.  * @return 密钥 
  99.  */ 
  100.  private static Key toKey(byte[] key,String algorithm){ 
  101.  //生成密钥 
  102.  return new SecretKeySpec(key, algorithm); 
  103.  } 
  104.  
  105.  /** 
  106.  * 使用HmacMD5消息摘要算法计算消息摘要 
  107.  * 
  108.  * @param data 做消息摘要的数据 
  109.  * @param key 密钥 
  110.  * @return 消息摘要(长度为16的字节数组) 
  111.  */ 
  112.  public static byte[] encodeHmacMD5(byte[] data, Key key){ 
  113.  Mac mac = null; 
  114.  try { 
  115.  mac = Mac.getInstance("HmacMD5"); 
  116.  mac.init(key); 
  117.  } catch (NoSuchAlgorithmException e) { 
  118.  e.printStackTrace(); 
  119.  return new byte[0]; 
  120.  }catch (InvalidKeyException e) { 
  121.  e.printStackTrace(); 
  122.  return new byte[0]; 
  123.  } 
  124.  return mac.doFinal(data); 
  125.  } 
  126.  
  127.  /** 
  128.  * 使用HmacMD5消息摘要算法计算消息摘要 
  129.  * 
  130.  * @param data 做消息摘要的数据 
  131.  * @param key 密钥 
  132.  * @return 消息摘要(长度为16的字节数组) 
  133.  */ 
  134.  public static byte[] encodeHmacMD5(byte[] data, byte[] key){ 
  135.  Key k = toKey(key, "HmacMD5"); 
  136.  return encodeHmacMD5(data, k); 
  137.  } 
  138.  
  139.  /** 
  140.  * 使用HmacSHA消息摘要算法计算消息摘要 
  141.  * 
  142.  * @param data 做消息摘要的数据 
  143.  * @param key 密钥 
  144.  * @return 消息摘要(长度为16的字节数组) 
  145.  */ 
  146.  public static byte[] encodeHmacSHA(byte[] data, Key key){ 
  147.  Mac mac = null; 
  148.  try { 
  149.  mac = Mac.getInstance("HmacSHA1"); 
  150.  mac.init(key); 
  151.  } catch (NoSuchAlgorithmException e) { 
  152.  e.printStackTrace(); 
  153.  return new byte[0]; 
  154.  }catch (InvalidKeyException e) { 
  155.  e.printStackTrace(); 
  156.  return new byte[0]; 
  157.  } 
  158.  return mac.doFinal(data); 
  159.  } 
  160.  
  161.  /** 
  162.  * 使用HmacSHA消息摘要算法计算消息摘要 
  163.  * 
  164.  * @param data 做消息摘要的数据 
  165.  * @param key 密钥 
  166.  * @return 消息摘要(长度为16的字节数组) 
  167.  */ 
  168.  public static byte[] encodeHmacSHA(byte[] data, byte[] key){ 
  169.  Key k = toKey(key, "HmacSHA1"); 
  170.  return encodeHmacSHA(data, k); 
  171.  } 
  172.  
  173.  /** 
  174.  * 使用HmacSHA256消息摘要算法计算消息摘要 
  175.  * 
  176.  * @param data 做消息摘要的数据 
  177.  * @param key 密钥 
  178.  * @return 消息摘要(长度为16的字节数组) 
  179.  */ 
  180.  public static byte[] encodeHmacSHA256(byte[] data, Key key){ 
  181.  Mac mac = null; 
  182.  try { 
  183.  mac = Mac.getInstance("HmacSHA256"); 
  184.  mac.init(key); 
  185.  } catch (NoSuchAlgorithmException e) { 
  186.  e.printStackTrace(); 
  187.  return new byte[0]; 
  188.  }catch (InvalidKeyException e) { 
  189.  e.printStackTrace(); 
  190.  return new byte[0]; 
  191.  } 
  192.  return mac.doFinal(data); 
  193.  } 
  194.  
  195.  /** 
  196.  * 使用HmacSHA256消息摘要算法计算消息摘要 
  197.  * 
  198.  * @param data 做消息摘要的数据 
  199.  * @param key 密钥 
  200.  * @return 消息摘要(长度为16的字节数组) 
  201.  */ 
  202.  public static byte[] encodeHmacSHA256(byte[] data, byte[] key){ 
  203.  Key k = toKey(key, "HmacSHA256"); 
  204.  return encodeHmacSHA256(data, k); 
  205.  } 
  206.  
  207.  
  208.  /** 
  209.  * 使用HmacSHA384消息摘要算法计算消息摘要 
  210.  * 
  211.  * @param data 做消息摘要的数据 
  212.  * @param key 密钥 
  213.  * @return 消息摘要(长度为16的字节数组) 
  214.  */ 
  215.  public static byte[] encodeHmacSHA384(byte[] data, Key key){ 
  216.  Mac mac = null; 
  217.  try { 
  218.  mac = Mac.getInstance("HmacSHA384"); 
  219.  mac.init(key); 
  220.  } catch (NoSuchAlgorithmException e) { 
  221.  e.printStackTrace(); 
  222.  return new byte[0]; 
  223.  }catch (InvalidKeyException e) { 
  224.  e.printStackTrace(); 
  225.  return new byte[0]; 
  226.  } 
  227.  return mac.doFinal(data); 
  228.  } 
  229.  
  230.  /** 
  231.  * 使用HmacSHA384消息摘要算法计算消息摘要 
  232.  * 
  233.  * @param data 做消息摘要的数据 
  234.  * @param key 密钥 
  235.  * @return 消息摘要(长度为16的字节数组) 
  236.  */ 
  237.  public static byte[] encodeHmacSHA384(byte[] data, byte[] key){ 
  238.  Key k = toKey(key, "HmacSHA384"); 
  239.  return encodeHmacSHA384(data, k); 
  240.  } 
  241.  
  242.  
  243.  
  244.  /** 
  245.  * 使用HmacSHA512消息摘要算法计算消息摘要 
  246.  * 
  247.  * @param data 做消息摘要的数据 
  248.  * @param key 密钥 
  249.  * @return 消息摘要(长度为16的字节数组) 
  250.  */ 
  251.  public static byte[] encodeHmacSHA512(byte[] data, Key key){ 
  252.  Mac mac = null; 
  253.  try { 
  254.  mac = Mac.getInstance("HmacSHA512"); 
  255.  mac.init(key); 
  256.  } catch (NoSuchAlgorithmException e) { 
  257.  e.printStackTrace(); 
  258.  return new byte[0]; 
  259.  }catch (InvalidKeyException e) { 
  260.  e.printStackTrace(); 
  261.  return new byte[0]; 
  262.  } 
  263.  return mac.doFinal(data); 
  264.  } 
  265.  
  266.  /** 
  267.  * 使用HmacSHA512消息摘要算法计算消息摘要 
  268.  * 
  269.  * @param data 做消息摘要的数据 
  270.  * @param key 密钥 
  271.  * @return 消息摘要(长度为16的字节数组) 
  272.  */ 
  273.  public static byte[] encodeHmacSHA512(byte[] data, byte[] key){ 
  274.  Key k = toKey(key, "HmacSHA512"); 
  275.  return encodeHmacSHA512(data, k); 
  276.  } 
  277.  
  278.  
  279.  private static String showByteArray(byte[] data){ 
  280.  if(null == data){ 
  281.  return null; 
  282.  } 
  283.  StringBuilder sb = new StringBuilder("{"); 
  284.  for(byte b:data){ 
  285.  sb.append(b).append(","); 
  286.  } 
  287.  sb.deleteCharAt(sb.length()-1); 
  288.  sb.append("}"); 
  289.  return sb.toString(); 
  290.  } 
  291.  
  292.  public static void main(String[] args) { 
  293.  // byte[] key = getHmaMD5key(); 
  294.  // byte[] key = getHmaSHAkey(); 
  295.  // byte[] key = getHmaSHA256key(); 
  296.  // byte[] key = getHmaSHA384key(); 
  297.  byte[] key = getHmaSHA512key(); 
  298.  
  299.  
  300.  System.out.println("加密密钥: byte[]:"+showByteArray(key).length()); 
  301.  
  302.  String data = "Mac数据"; 
  303.  System.out.println("加密前数据: string:"+data); 
  304.  System.out.println("加密前数据: byte[]:"+showByteArray(data.getBytes())); 
  305.  System.out.println(); 
  306.  // byte[] encodeData = encodeHmacMD5(data.getBytes(), key); 
  307.  // byte[] encodeData = encodeHmacSHA(data.getBytes(), key); 
  308.  // byte[] encodeData = encodeHmacSHA256(data.getBytes(), key); 
  309.  // byte[] encodeData = encodeHmacSHA384(data.getBytes(), key); 
  310.  byte[] encodeData = encodeHmacSHA512(data.getBytes(), key); 
  311.  System.out.println("加密后数据: byte[]:"+showByteArray(encodeData).length()); 
  312.  System.out.println("加密后数据: byte[]:"+encodeData.length); 
  313.  System.out.println("加密后数据: hexStr:"+Hex.encodeHexStr(encodeData)); 
  314.  System.out.println(); 
  315.  } 




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论