最近笔者对RC6加解密进行了研究,己完善了《朱明海--维普资讯网--对称加解密算法RC6的C#实现》的程序,源码在我的博客上:http://blog.csdn.net/ExcelWord/archive/2010/11/29/6041864.aspx,这只是对明文不超远32个ASCII字符的加解密,也不支持中文方法,通过今天的反复研究,终于实现了在winform和webform上的中文加密解密程序!
  其源码如下:
第一
新建的一个类:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace MeStrBainRC6
{
    public class RC6
    {
        /// <summary>
        /// 对称加解密算法RC6的C#中文实现
        /// 公开维普网_朱明海先生未公布的源码
        /// 程序完善设计者:四川威远_老耙子 先生
        /// 2010-11-30
        /// 如有需要,请与本人联系。
        /// Mail:chscwyyg@163.com 电话:0832-8229211
        /// </summary>
        private string m_sEncryptionKey;                                             //密码方法通过KEY属性返回值
        private string m_sCryptedText;                                                //加密解密字符串返回值
        public int m_nChipherlen;                                                   //密码字节数,控制加密最低为128,最好256,间192,有三种选择种16,24,32
        private const int m_nWord = 32;
        private const int r = 20;
        private const int c = 4;
        private uint[] m_nKeyExpandBox;                                              //系统密钥数组
        uint[] n_WordBox;                                                            //用户私有密钥
        public Encoding Enc_default = Encoding.Unicode;

/// <summary>
        /// 左位移运算函数
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="w"></param>
        /// <returns></returns>
        ///
        public uint ROTL(uint x, uint y, int w)
        { return ((x << (int)(y & (0xFF))) | (x >> (int)(w - (y & (0xFF))))); }//或:return ((x << (int)(y & (w-1))) | (x >> (int)(w - (y & (w-1)))));

/// <summary>
        /// 右位移运算函数
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="w"></param>
        /// <returns></returns>
        public uint ROTR(uint x, uint y, int w)
        { return ((x >> (int)(y & (0xFF))) | (x << (int)(w - (y & (0xFF))))); }//或:return ((x >> (int)(y & (w-1))) | (x << (int)(w - (y & (w-1)))));

/// <summary>
        /// 构造函数
        /// </summary>
        public RC6()
        {
            IV = 16;                                        //如果用户没有设置加密方式系统默认为128位加密
            //                                                IV返回m_nChipherlen
            m_nKeyExpandBox = new uint[8 * m_nChipherlen];  //密钥数组大小为加IV*8
        }
        /// <summary>
        /// 构造函数可输入加密向量
        /// </summary>
        /// <param name="iv"></param>
        public RC6(int iv)
        {
            IV = iv;            //返回       m_nChipherlen
            _IV();              //验证用户输入的iv(m_nChipherlen)是否合法!
            this.m_nKeyExpandBox = new uint[8 * m_nChipherlen];
        }
        /// <summary>
        /// 定义一个属性,通过属性输入用户密钥并返回
        /// 存储到m_sEncryptionKey
        /// </summary>
        public string KEY
        {
            get { return this.m_sEncryptionKey; }
            set { this.m_sEncryptionKey = value; }
        }

/// <summary>
        /// 加密向量选择
        /// 128方式IV=16
        /// 192方法IV=24
        /// 256方法IV=32
        /// </summary>
        public int IV
        {
            get { return m_nChipherlen; }
            set { m_nChipherlen = value; }
        }

/// <summary>
        /// 加密向量验证函数
        /// 有错误返回最小或最大的向量设置
        /// </summary>
        /// <returns></returns>
        public int _IV()
        {
            if (m_nChipherlen < 16) m_nChipherlen = 16;
            if (m_nChipherlen > 32) m_nChipherlen = 32;
            return m_nChipherlen;
        }

/// <summary>
        /// string类型Unicode字符集转为字节流char[];
        /// </summary>
        /// <returns></returns>
        private char[] String_Unicode()
        {
            string prssword = this.m_sEncryptionKey;
            prssword = (prssword.Length % m_nChipherlen != 0 ? prssword.PadRight(prssword.Length + (m_nChipherlen - (prssword.Length % m_nChipherlen)), '/0') : prssword);

byte[] asciiBytes = Encoding.Convert(Encoding.Unicode, Encoding.ASCII, Encoding.Unicode.GetBytes(prssword));
            char[] asciiChars = new char[Encoding.ASCII.GetCharCount(asciiBytes, 0, asciiBytes.Length)];             //等价=====char[] asciiChars = new char[asciiBytes.Length];
            Encoding.ASCII.GetChars(asciiBytes, 0, asciiBytes.Length, asciiChars, 0);
            return asciiChars;
        }

/// <summary>
        /// 初始化函数用户密钥
        /// 通过KeySteup函数扩展并混合密钥
        /// </summary>
        ///
        void KeySteup()
        {
            uint P32 = 0xb7e15163;
            uint Q32 = 0x9e3779b9;
            uint A, B;
            A = B = 0;
            int i, j;
            i = j = 0;

char[] key = String_Unicode();                       //密码类型转换,String型转换为char[],下面String_Unicode()函数返回值

n_WordBox = new uint[m_nChipherlen / 4];            //选择  16  or  24 or 32  128,192,256加密方式,4,6,8
            uint temp;

//密钥类型转换  string类型转换为uint
            for (j = 0; j < m_nChipherlen; j++)   
            {                                                                     
                temp = (uint)(key[j] & 0xFF) << (8 * (j % 4));
                n_WordBox[j / 4] += (uint)temp;   //循环四次生成一个uint   
                // 在BinaryReader中间流中,ReadUint32() 属性取代了上属循环生成一个UInt32对象,因此BinaryReader.ReadUInt32();更简单,
                //之所以RC6未获胜的原因之一

}

//密钥扩展                                                              m_nChipherLen=32   or 24 or 16  
            this.m_nKeyExpandBox[0] = P32;                                           //扩展密钥初始化,0位置赋值P32 
            for (j = 1; j < 2 * m_nChipherlen + 4; j++)                              //m_nChipherlen是加密向量,反应加密方式128,192,256三种
            { this.m_nKeyExpandBox[j] = m_nKeyExpandBox[j - 1] + Q32; }

int k = 3 * Math.Max(n_WordBox.Length, 2 * m_nChipherlen + 4);
            for (j = 0, i = 0; k > 0; k--)
            {
                A = ROTL(m_nKeyExpandBox[i] + A + B, 3, m_nWord);                   //混合密钥
                m_nKeyExpandBox[i] = (byte)A;
                B += A;
                B = ROTL(n_WordBox[j] + A + B, A + B, m_nWord);                   //m_nKeyExpandBox[ii]的值混合到用户密钥中                        
                n_WordBox[j] = B;                                                 //这里是仍然是uint,生成新用户密码,32位值。提取见上面方法  [***  1]
                i = (i + 1) % (2 * m_nChipherlen + 4);                              //取模运算确保对应 m_nKeyExpandBox和 n_WordBox数组不越界                    
                j = (j + 1) % n_WordBox.Length;                                   //n_WordBox.Length  分别代表 4,6,8
            }
        }
 /// <summary>
 /// 加密UInt32数组
 /// 加密前必须将明文转换为32位的uint[],r1
 /// 通过该函数r1与密钥进行混合输出uint[],r2
 /// </summary>
 /// <param name="r1">加密前的UInt32数组</param>
 /// <param name="r2">加密后的UInt32数组</param>

void Encode(uint[] r1, uint[] r2)
        {
            uint A, B, C, D, U, T, temp;
            A = r1[0];
            B = r1[1];
            C = r1[2];
            D = r1[3];

U = T = temp = 0;

B += m_nKeyExpandBox[0];
            D += m_nKeyExpandBox[1];

for (int j = 1; j <= m_nChipherlen; j++)              //左移计算并位置换位,矩阵运算
            {
                U = ROTL(D * (2 * D + 1), 5, m_nWord);            //左移5位,这里其实m_nWord没有多少实用价值,因为本类未使用return ((x << (int)(y & (w-1))) | (x >> (int)(w - (y & (w-1)))))
                T = ROTL(B * (2 * B + 1), 5, m_nWord);
                A = ROTL(A ^ T, U, m_nWord) + m_nKeyExpandBox[2 * j];
                C = ROTL(C ^ U, T, m_nWord) + m_nKeyExpandBox[2 * j + 1];
                temp = A;                                         //中间变量temp的值为A
                A = B;                                            //B的值赋值给A,就是B的位置移动到了A
                B = C;                                            //C的值赋值给B,就是C的位置移动到了B
                C = D;                                            //D的值赋值给C,就是D的位置移动到了C
                D = temp;                                         //A的值赋值给D,就是A的位置移动到了D

}
            A += m_nKeyExpandBox[2 * r + 2];
            C += m_nKeyExpandBox[2 * r + 3];
            r2[0] = A;
            r2[1] = B;
            r2[2] = C;
            r2[3] = D;

}
/// <summary>
/// 解密UInt32数组
/// 解密前必须将密文转换为32位的uint[],r1
/// 通过该函数r1与密钥混合输出解密后uint[],r2
/// </summary>
/// <param name="r1"></param>
/// <param name="r2"></param>
        void Decode(uint[] r1, uint[] r2)
        {
            uint A, B, C, D, T, U, temp; T = U = 0; //4个32位循环赋值的uint(A,B,C,D)
            A = B = C = D = 0;
            temp = 0;
            A = r1[0];
            B = r1[1];
            C = r1[2];
            D = r1[3];

C -= m_nKeyExpandBox[2 * r + 3];
            A -= m_nKeyExpandBox[2 * r + 2];

for (int j = 1; j <= m_nChipherlen; j++)
            {
                temp = D;
                D = C;
                C = B;
                B = A;
                A = temp;
                U = ROTL(D * (2 * D + 1), 5, m_nWord);
                T = ROTL(B * (2 * B + 1), 5, m_nWord);
                C = ROTR(C - m_nKeyExpandBox[2 * (m_nChipherlen - j) + 3], T, m_nWord) ^ U;
                A = ROTR(A - m_nKeyExpandBox[2 * (m_nChipherlen - j) + 2], U, m_nWord) ^ T;
            }
            D -= m_nKeyExpandBox[1];
            B -= m_nKeyExpandBox[0];

r2[0] = A;
            r2[1] = B;
            r2[2] = C;
            r2[3] = D;

}
/// <summary>
/// 加密方法
/// </summary>
/// <param name="str">加密的明文</param>
        /// <param name="prssword">用户加密的密码</param>
/// <returns></returns>
        public  string Encrypt(string str, string prssword)
        {
            KEY = prssword;  //用户密码,通过KEY属性写入
            KeySteup();      //密码输入后与系统混合后成密钥

long len;
            byte[] input;
            using (MemoryStream obj = new MemoryStream(Encoding.Default.GetBytes(str)))        //临时的MemoryStream流变量obj,完成循环后自行销毁
            {
                long temp = obj.Length;
                temp = (temp % 16 != 0 ? temp + (16 - (obj.Length % 16)) : temp); obj.Close();//验证字符转换成字节byte其长度是否满足被16整除,不足长度补足长度,
                /*                                                                              满足16个字节用ReadUInt32()方法转换为4个uint变量要求,以用于加密  */
                len = temp; input = new byte[len];
                byte[] Obj = obj.ToArray();
                for (int i = 0; i < Obj.Length; i++) { input[i] = Obj[i]; }
            }

MemoryStream Stream = new MemoryStream(input);                               //输入流容器
            BinaryReader Br = new BinaryReader(Stream);                                  //该对象是Stream的中间容器,俱有Read属性,及读取属性

uint[] r1 = new uint[Stream.Length / 4];   //                                //为什么这是input.Length/4;因为是从Br流中取出4个字节组成一个Uint的32位值
            long UintLen = Stream.Length;            //
            int Len1 = 0;
            while (UintLen > 0)
            {   //                                  //从流中读取字节转换Uint32
                r1[Len1] = Br.ReadUInt32();         //从Br流中取出byte的四个字节值组成新Uint,并且1字节不移位,2字节左移位8位,3字节左移16位,4字节左移位24(所以这里简化了位移计算)
                Len1++;
                UintLen -= 4;                       //每次取4个字节后,总长度减4
            } Br.Close(); Stream.Close();

MemoryStream bw = new MemoryStream();  //输出流容器
            BinaryWriter Bw = new BinaryWriter(bw);//为bw的中间容器,俱有Write属性,及写入流属性

for (int i = 0; i < r1.Length; i += 4)
            {
                uint[] R1 = new uint[4];
                uint[] R2 = new uint[4];
             
               for (int z = 0; z < 4; z++) { R1[z] = r1[i+z];}

Encode(R1, R2);

for (int z = 0; z < 4; z++){ Bw.Write(R2[z]); }
            }  Bw.Close(); bw.Close();

return Convert.ToBase64String(bw.ToArray());// 从流bw转换成byte字节,以Base64String字符串的形式输出
        }
/// <summary>
/// 解密函数返回解密的字符串
/// </summary>
/// <param name="str">待解密的密文</param>
/// <param name="prssword">用户解密的密码</param>
/// <returns></returns>
        public string Decrypt(string str, string prssword)
        {

KEY = prssword;  //用户密码,通过KEY属性写入
            KeySteup();      //密码输入后与系统混合后成密钥

long len;
            byte[] input;
            using (MemoryStream obj = new MemoryStream(Convert.FromBase64String(str)))        //定义一个临时的MemoryStream流变量obj,与流输出的字符串还原为byte字节
            {
                long temp = obj.Length;
                temp = (temp % 16 != 0 ? temp + (16 - (obj.Length % 16)) : temp); obj.Close();//验证字符转换成字节byte其长度是否满足被16整除,不足长度补足长度,
                /*                                                                              满足16个字节用ReadUInt32()方法转换为4个uint变量要求,以用于解密  */
                len = temp; input = new byte[len];
                byte[] Obj = obj.ToArray();
                for (int i = 0; i < Obj.Length; i++) { input[i] = Obj[i]; }
            }

MemoryStream Stream = new MemoryStream(input);                                   //输入流容器
            BinaryReader Br = new BinaryReader(Stream);                                      //该对象是Stream的中间容器,俱有Read属性,及读取属性

uint[] r1 = new uint[Stream.Length / 4];   //                                    //从Br取出4个字节组成一个Uint的32位值
            long UintLen = Stream.Length;             //                                       字节总长度;
            int Len1 = 0;
            while (UintLen > 0)
            {   //                                  //从流中读取字节转换Uint32
                r1[Len1] = Br.ReadUInt32();         //从Br流中取出byte的四个字节值组成新Uint,并且1字节不移位,2字节左移位8位,3字节左移16位,4字节左移位24(所以这里简化了位移计算)
                Len1++;                             //自加1后再循环
                UintLen -= 4;                       //每次取4个字节后,总长度减4
            } Br.Close(); Stream.Close();

MemoryStream bw = new MemoryStream();  //输出流容器
            BinaryWriter Bw = new BinaryWriter(bw);//为bw的中间容器,俱有Write属性,及写入流属性

for (int i = 0; i < r1.Length; i += 4)
            {
                uint[] R1 = new uint[4];
                uint[] R2 = new uint[4];
                for (int z = 0; z < 4; z++)
                { R1[z] = r1[i + z]; }

Decode(R1, R2);
                for (int z = 0; z < 4; z++)
                { Bw.Write(R2[z]); }
            } Bw.Close(); bw.Close();
           
            return Encoding.Default.GetString(bw.ToArray()); ;

}

static void Main(string[] agrs)
        {
            RC6 obj = new RC6(32);
            string str = "支持中文的RC6加密解程序abcdefghijklmnopqrstuvwxyz";  //明文
            Console.WriteLine("加密前的明文是: {0}", str);
            string pwd="*&^*&^%$@!$~`:;'///";                                  //用户密码
            string str1=obj.Encrypt(str, pwd);                                 //加密后的密文
            Console.WriteLine("加密后的密后的密文是:{0}",str1);
            string str2 = obj.Decrypt(str1, pwd);                              //解密后明文
            Console.WriteLine("解密后的生成字符串是:{0}", str2);
            Console.ReadKey();
        }
    }
}

第二: 在Asp运用:

前台程序:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="RC6_Web_Form._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>无标题页</title>
</head>
<body style="font-size:12px;">
    <form id="form1" runat="server">
    <div>
     <table border="0" cellpadding="0" cellspacing="0" style="font-size:12px;">
        <tr>
           <td>明文区<br /><asp:TextBox ID="TextBox1" runat="server" Height="72px" TextMode="MultiLine"></asp:TextBox></td>
           <td>选择加密方式<br /><asp:DropDownList ID="DropDownList1" runat="server" Width="156px"  AutoPostBack="true">
               <asp:ListItem>128位加密解密</asp:ListItem>
               <asp:ListItem>192位加密解密</asp:ListItem>
               <asp:ListItem>256位加密解密</asp:ListItem>
               </asp:DropDownList><br /><br /><br />用户密码<br /><asp:TextBox ID="TextBox2" runat="server"></asp:TextBox></td>
           <td><asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="加密" /><br /></td>
        </tr>
     </table>
    </div>
    <div>密文区<br />
        <asp:TextBox ID="TextBox3" runat="server" Height="64px" TextMode="MultiLine" Width="336px"></asp:TextBox>
        <asp:Button ID="Button2" runat="server" Text="解密" OnClick="Button2_Click" /><br />
        解密结果:<br />
        <asp:TextBox ID="TextBox4" runat="server" Height="80px" TextMode="MultiLine" Width="336px"></asp:TextBox></div>
    </form>
</body>
</html>

后台程序:
添加类的引用,

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using MeStrBainRC6;   //添加类引用
namespace RC6_Web_Form
{
    public partial class _Default : System.Web.UI.Page
    {
        public int round;
        protected void Page_Load(object sender, EventArgs e)
        {
              
        }

protected void Button1_Click(object sender, EventArgs e)
        {
            round=Return(this.DropDownList1);
            MeStrBainRC6.RC6 obj = new MeStrBainRC6.RC6(round);
           
            if (TextBox1.Text != null || TextBox2.Text != null)
            { TextBox3.Text = ""; TextBox3.Text = obj.Encrypt(TextBox1.Text, TextBox2.Text); }
            TextBox2.Enabled = false; DropDownList1.Enabled = false;
            TextBox4.Text = "";
        }

protected void Button2_Click(object sender, EventArgs e)
        {
            round = Return(this.DropDownList1);
            MeStrBainRC6.RC6 obj = new MeStrBainRC6.RC6(round);
            if (TextBox3.Text != null || TextBox2.Text != null)
            { TextBox4.Text = ""; TextBox4.Text = obj.Decrypt(TextBox3.Text, TextBox2.Text); }
            TextBox2.Enabled = true; DropDownList1.Enabled = true;
        }
        private int Return(DropDownList ojb)
        {
            string str = ojb.SelectedItem.Text;
            switch (str)
            {
                case "128位加密解密": round = 16; break;
                case "192位加密解密": round = 24; break;
                case "256位加密解密": round = 32; break;
                default: break;
            }
            return round;
        }
    }
}

以下程序运行情况:


以上程序在winform和webform上测试通过。

有什么好的建议和方法请大家提出来!

Asp.net程序实现RC6_中文加解密相关推荐

  1. 中文加解密异常的问题

    在使用AES加密时要注意指定字符编码,要使用String.getBypes(String charsetName)而不能使用String.getBytes(),后者源码中有一句: String csn ...

  2. 微信小程序与服务器对称加解密,细说CryptoJs使用(微信小程序加密解密)

    前言 CryptoJs是google推出的一款前段解密类库.功能强大,包含很多的前段解密算法. 一.google下载地址: 二次开发版本 google原版地址 二.常用方法 Testing webso ...

  3. 《ASP.NET Core 6框架揭秘》实例演示[19]:数据加解密与哈希

    数据保护(Data Protection)框架旨在解决数据在传输与持久化存储过程中的一致性(Integrity)和机密性(confidentiality)问题,前者用于检验接收到的数据是否经过篡改,后 ...

  4. 微信小程序前端RSA加解密

     开门见山地说,希望各位前端不要搜到这篇文章,因为我总感觉在小程序端去做RSA的加解密总有种脱了裤子放屁多此一举的感觉.但是需求来的时候总是说不准的,接下来我就给大家推荐一种在小程序端比较方便,操作不 ...

  5. 加解密程序之中间件思想的运用

    近期在工作中遇到一个加解密的集成需求,过程算得上是一波三折,在此记录以供思路分享,并便于日后翻阅. 1.需求背景: 客户引入数据时上传的excel是加密文件,由于系统无法直接解析加密文件导致引入失败. ...

  6. 基于安卓系统的SM4-SM2/3加解密软件开发报告

    目 录 第一章需求分析 1.1软件功能需求 1.2平台需求 1.3人员分工 第二章概要设计 2.1 软件开发平台 2.2 软件基本流程 2.3 UML图 第三章 程序详细设计 3.1 程序接口设计 3 ...

  7. Delphi RSA加解密(一)

    感谢.感谢.感谢大佬的分享,https://github.com/ZYHPRO/RSAEncryptAndDecode 目录 1. 前言 2. 准备工作 3. Demo注意事项说明 3.1 公钥.私钥 ...

  8. ASP.NET Core 数据加解密的一些坑

    点击蓝字 关注我 ASP.NET Core 给我们提供了自带的Data Protection机制,用于敏感数据加解密,带来方便的同时也有一些限制可能引发问题,这几天我就被狠狠爆了一把 我的场景 我的博 ...

  9. 某付宝APP之某加油小程序对称加解密算法解析

    前言 前几天发了一个某付宝小程序的sign参数md5加密拿到明文参数的帖子- 又发现一个别的小程序,好像是用的对称加密,耐不住好奇心,就试了试-结果成功实现了加解密的操作.遂发帖记录一下. 工具 fi ...

最新文章

  1. 来!一起搭建个永久运行的个人服务器吧!
  2. Pywinauto 应用后端类型选择错误:AttributeError: ‘NoneType‘ object has no attribute ‘backend‘. 原因及解决办法
  3. ync 小技巧-14-为用户启用统一的联系人存储库-Lync-无联系人
  4. 计算机图形学-MFC界面分屏操作
  5. Django 【第二十篇】后端CORS解决跨域问题
  6. SecureCRT使用过程中 光标会丢失的问题
  7. 【LeetCode 327】区间和的个数
  8. 珍爱网html模板,python爬虫基础实战:爬取珍爱网征婚女士信息,爬取Discuz论坛发帖和回帖代码案例...
  9. VC下揭开“特洛伊木马”的隐藏面纱
  10. 前端利用jQuery设置日期选择框
  11. raw os 之状态机编程
  12. 电气火灾的危害及预防
  13. 软件架构设计-大型网站技术架构于业务架构融合之道——部分知识点总结【未完】
  14. 无线射频专题《协议类,IEEE 802.11/802.11b/802.11a/802.11g/802.11n/802.11ac标准简介》
  15. Word插入Latex公式的几种方式~(TeXsWord、EqualX、Aurora、向Office插入LaTeX公式的工具)...
  16. 俩个PC机通过串行口互联,实现件的无差错传输。程序必须用中断方式来完成任务
  17. String的属性和方法实例 Dart
  18. 搜狗输入法突然变成繁体怎么解决?
  19. 山东科技大学新增计算机专业,山科大新增物联网专业 全国30高校获批此专业...
  20. _ext.cpython-37m-x86_64-linux-gnu.so: undefined symbol: _ZN6caffe26deta

热门文章

  1. python执行CMD指令,并获取返回
  2. PV、PVC、StorageClass讲解
  3. 《苏菲的世界》读后感
  4. springboot订单超时和超时提醒
  5. Angular慕课网
  6. 大数据周会-本周学习内容总结010
  7. [转] Real-World Concurrency
  8. 如何在GitHub上创建自己的仓库?
  9. matlab tolfun,非线性方程组求解问题(关于TolFun设置问题)
  10. 麻烦你先搞懂这几个问题,简历再写熟悉数据库!!!