目录
MySQL新特性之mysql_config_editor源码解析
首页 后端开发 php教程 MySQL新特性之mysql_config_editor源码解析_PHP教程

MySQL新特性之mysql_config_editor源码解析_PHP教程

Jul 12, 2016 am 09:01 AM
android

MySQL新特性之mysql_config_editor源码解析

从mysql5.6开始,mysql推出了加密工具mysql_config_editor。在此之前我们通过将账号和密码明文放入my.cnf,从而使用mysql客户端登录时,无需指定账号密码就可以登录数据库。而有了mysql_config_editor工具之后,我们将加密后的账号密码放入二进制文件。在登录时,客户端通过解密该文件来登录数据库。由于加密解密都在内存中进行,所以无法明文的显示文件内容。只要我们将文件权限保存好,就可以防止不怀好意的人解密我们的数据库密码了.

mysql_config_editor的使用过程如下: mysql_config_editor set --login-path=client --host=localhost --user=localuser --password

这样我们就配置了一个为本地的数据源信息: login-path :指定通过mysql客户端登录时的标识host:我们要连接的数据库user: 通过本地连接数据库时,使用的账号password:指定通过本地连接时,使用的数据库密码(这里假设输入的密码为password1)

当然,如果通过远程连接,我们可能还要加上特定的端口信息。这样,当我们登录数据库时,只需要如下命令就可以连接到该数据库了:mysql —login-path=client
这样我们就连接到本地数据库了。
下面我们来看看mysql_config_editor的细节部分: 由于该工具包含set/remove/print/reset/help,所以我们仅分析set功能的实现: set功能是通过set_command函数实现的,该函数主要用于配置账号密码等数据源信息,并将该信息存储到二进制文件:

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>static int set_command(void)<br /> </li><li>{<br /></li><li>DBUG_ENTER("set_command");<br /></li><li><br /></li><li>DYNAMIC_STRING file_buf, path_buf;<br /></li><li>init_dynamic_string(&path_buf, "", MY_LINE_MAX, MY_LINE_MAX);<br /></li><li>init_dynamic_string(&file_buf, "", file_size, 3 * MY_LINE_MAX);<br /></li><li><br /></li><li>if (tty_password)<br /></li><li>opt_password= get_tty_password(NullS); <br /></li><li>if (file_size)<br /></li><li>{<br /></li><li>if (read_and_decrypt_file(&file_buf) == -1) //如果文件存在,就读取文件,并将文件的密文解密后存放到file_buf中.<br /></li><li>goto error;<br /></li><li>}<br /></li><li><br /></li><li>dynstr_append(&path_buf, "["); /* --login=path */ <br /></li><li>if (opt_login_path)<br /></li><li>dynstr_append(&path_buf, opt_login_path);<br /></li><li>else<br /></li><li>dynstr_append(&path_buf, "client");<br /></li><li>dynstr_append(&path_buf, "]");<br /></li><li><br /></li><li>if (opt_user) /* --user */<br /></li><li>{<br /></li><li>dynstr_append(&path_buf, "\nuser = ");<br /></li><li>dynstr_append(&path_buf, opt_user);<br /></li><li>}<br /></li><li><br /></li><li>if (opt_password) /* --password */<br /></li><li>{<br /></li><li>dynstr_append(&path_buf, "\npassword = ");<br /></li><li>dynstr_append(&path_buf, opt_password);<br /></li><li>}<br /></li><li><br /></li><li>if (opt_host) /* --host */<br /></li><li>{<br /></li><li>dynstr_append(&path_buf, "\nhost = ");<br /></li><li>dynstr_append(&path_buf, opt_host);<br /></li><li>}<br /></li><li><br /></li><li>if (opt_socket)<br /></li><li>{<br /></li><li>dynstr_append(&path_buf, "\nsocket = ");<br /></li><li>dynstr_append(&path_buf, opt_socket);<br /></li><li>}<br /></li><li><br /></li><li>if (opt_port)<br /></li><li>{<br /></li><li>dynstr_append(&path_buf, "\nport = ");<br /></li><li>dynstr_append(&path_buf, opt_port);<br /></li><li>}<br /></li><li><br /></li><li>dynstr_append(&path_buf, "\n");<br /></li><li><br /></li><li>/* Warn if login path already exists */<br /></li><li>if (opt_warn && ((locate_login_path (&file_buf, opt_login_path)) //判断该login-path是否已经存在<br /></li><li>!= NULL))<br /></li><li>{<br /></li><li>int choice;<br /></li><li>printf ("WARNING : \'%s\' path already exists and will be "<br /></li><li>"overwritten. \n Continue? (Press y|Y for Yes, any "<br /></li><li>"other key for No) : ",<br /></li><li>opt_login_path);<br /></li><li>choice= getchar();<br /></li><li><br /></li><li>if (choice != (int) 'y' && choice != (int) 'Y’) //如果login-path存在是否选择覆盖<br /></li><li>goto done; /* skip */<br /></li><li>}<br /></li><li><br /></li><li>/* Remove the login path. */<br /></li><li>remove_login_path(&file_buf, opt_login_path); //从原来文件中读取的内容中,删掉该login-path信息<br /></li><li><br /></li><li>/* Append the new login path to the file buffer. */<br /></li><li>dynstr_append(&file_buf, path_buf.str); //将该login-path的信息加到file_buf的末尾<br /></li><li><br /></li><li>if (encrypt_and_write_file(&file_buf) == -1) //将包含新的log-path的所有信息和原来的信息加密写入文件<br /></li><li>goto error;<br /></li><li><br /></li><li>done:<br /></li><li>dynstr_free(&file_buf);<br /></li><li>dynstr_free(&path_buf);<br /></li><li>DBUG_RETURN(0);<br /></li><li><br /></li><li>error:<br /></li><li>dynstr_free(&file_buf);<br /></li><li>dynstr_free(&path_buf);<br /></li><li>DBUG_RETURN(-1);<br /></li><li>} </li></ol>
登录后复制

代码的具体逻辑如下:


在这里我们重点看看其中涉及的几个重要的函数:read_and_decrypt_file (读取文件内容,并解密后放到动态字符缓冲中)locate_login_path(判断该login-path是否已经存在)remove_login_path(如果login-path存在,则删除该login-path)dynstr_append(&file_buf, path_buf.str); 将新的login-path添加到file_buf 末尾encrypt_and_write_file(&file_buf) 将file_buf中的信息解码后写入到文件中

首先我们来看看加密后的文件格式如下:


这里我们假设之前已经存在加密的文件了.由于加密文件的前4个byte为’\0’,是未使用的,所以跳过解密环节。之后,紧接着的20个bytes是存放的对称加密算法的秘钥,而这部分内容在read_and_decrypt_file(read_login_key获取)调用之前已经读取取到,所以也要跳过。因此read_and_decrypt_file的过程如下:

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>/*<br /> </li><li>Header length for the login file.<br /></li><li>4-byte (unused) + LOGIN_KEY_LEN<br /></li><li>*/<br /></li><li>#define MY_LOGIN_HEADER_LEN (4 + LOGIN_KEY_LEN)<br /></li><li>static int read_and_decrypt_file(DYNAMIC_STRING *file_buf)<br /></li><li>{<br /></li><li>DBUG_ENTER("read_and_decrypt_file");<br /></li><li><br /></li><li>char cipher[MY_LINE_MAX], plain[MY_LINE_MAX];<br /></li><li>uchar len_buf[MAX_CIPHER_STORE_LEN];<br /></li><li>int cipher_len= 0, dec_len= 0;<br /></li><li><br /></li><li>/* Move past key first. */<br /></li><li>if (my_seek(g_fd, MY_LOGIN_HEADER_LEN, SEEK_SET, MYF(MY_WME)) //跳过之前的unused bytes和login key部分<br /></li><li>!= (MY_LOGIN_HEADER_LEN))<br /></li><li>goto error; /* Error while seeking. */<br /></li><li><br /></li><li>/* First read the length of the cipher. */<br /></li><li>while (my_read(g_fd, len_buf, MAX_CIPHER_STORE_LEN, //获取密文的长度<br /></li><li>MYF(MY_WME)) == MAX_CIPHER_STORE_LEN)<br /></li><li>{<br /></li><li>cipher_len= sint4korr(len_buf); //将密文的长度转换成整形<br /></li><li><br /></li><li>if (cipher_len > MY_LINE_MAX)<br /></li><li>goto error;<br /></li><li><br /></li><li>/* Now read 'cipher_len' bytes from the file. */<br /></li><li>if ((int) my_read(g_fd, (uchar *) cipher, cipher_len, MYF(MY_WME)) == cipher_len) //读取相应密文长度的密文<br /></li><li>{<br /></li><li>if ((dec_len= decrypt_buffer(cipher, cipher_len, plain)) < 0) //解密该密文<br /></li><li>goto error;<br /></li><li><br /></li><li>plain[dec_len]= 0;<br /></li><li>dynstr_append(file_buf, plain); //将解密后的密文追加到file_buf中<br /></li><li>}<br /></li><li>}<br /></li><li>verbose_msg("Successfully decrypted the login file.\n");<br /></li><li>DBUG_RETURN(0);<br /></li><li>error:<br /></li><li>my_perror("couldn't decrypt the file");<br /></li><li>DBUG_RETURN(-1);<br /></li><li>} </li></ol>
登录后复制

所以该函数的过程,就变为下面四个步骤的重复,只到文件中所有的密文都解密。这样,file_buf中就包含了所有的文件的明文信息:1.获取密文的长度2.根据获取的长度,读取文件中的密文3.根据读取到的密文,进行解密4.将解密后的内容,追加到file_buf缓冲区中。
在函数中,我们看到会将获取到的密文的长度,通过sint4korr转换,那是为什么呢 ?从上面我们可以知道,一个cipher其实有一个 4bytes的长度+cipher的字符串所以,通过int4store 将cipher的长度存储在cipher字符串的前4个bytes中,通过sint4korr将cipher前4个bytes中的值转化为实际的cipher长度:

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>#define int4store(T,A) do { *((char *)(T))=(char) ((A));\<br /> </li><li>*(((char *)(T))+1)=(char) (((A) >> 8));\<br /></li><li>*(((char *)(T))+2)=(char) (((A) >> 16));\<br /></li><li>*(((char *)(T))+3)=(char) (((A) >> 24));\<br /></li><li>} while(0)<br /></li><li><br /></li><li>#define sint4korr(A) (int32) (((int32) ((uchar) (A)[0])) +\<br /></li><li>(((int32) ((uchar) (A)[1]) << 8)) +\<br /></li><li>(((int32) ((uchar) (A)[2]) << 16)) +\<br /></li><li>(((int32) ((int16) (A)[3]) << 24))) </li></ol>
登录后复制

接下来再看看locate_login_path函数的实现:

  1. static char* locate_login_path(DYNAMIC_STRING *file_buf, const char *path_name)
  2. {
  3. DBUG_ENTER("locate_login_path");

  4. char *addr= NULL;
  5. DYNAMIC_STRING dy_path_name;

  6. init_dynamic_string(&dy_path_name, "", 512, 512); // 初始化dy_path_name动态字符串

  7. //将dy_path_name 设置为[path_name]
  8. dynstr_append(&dy_path_name, "\n[“);
  9. dynstr_append(&dy_path_name, path_name);
  10. dynstr_append(&dy_path_name, "]");

  11. //检查第一个login-path是否就是要寻找的login-path
  12. /* First check if it is the very first login path. */
  13. if (file_buf->str == strstr(file_buf->str, dy_path_name.str + 1))
  14. addr= file_buf->str;
  15. /* If not, scan through the file. */
  16. else
  17. {
  18. addr= strstr(file_buf->str, dy_path_name.str);
  19. if (addr)
  20. addr ++; /* Move past '\n' */
  21. }

  22. dynstr_free(&dy_path_name);
  23. DBUG_RETURN(addr); //返回找到的login-path在file_buf的首地址
  24. }
该函数主要是寻找login-path是否能已经存在,如果已经存在,返回该login-path在file_buf中的首地址。
如果该login-path已经存在,那么我们可能会选择remove该login-path,然后在添加该login-path。

接下来我们看看removelogin-path的实现:

  1. static void remove_login_path(DYNAMIC_STRING *file_buf, const char *path_name)
  2. {
  3. DBUG_ENTER("remove_login_path");

  4. char *start=NULL, *end= NULL;
  5. int to_move, len, diff;
  6. if((start= locate_login_path(file_buf, path_name)) == NULL) //如果该login-path不存在,直接结束
  7. /* login path was not found, skip.. */
  8. goto done;

  9. end= strstr(start, "\n[“); //end为从start开始寻找,下一个login-path的起始位置

  10. if (end) //如果该login-path是file_buf中间的某一个login-path
  11. {
  12. end ++; /* Move past '\n' */
  13. len= ((diff= (start - end)) > 0) ? diff : - diff;
  14. to_move= file_buf->length - (end - file_buf->str);
  15. }
  16. else //如果该login-path是该file_buf中最后一个log-path
  17. {
  18. *start= '\0';
  19. file_buf->length= ((diff= (file_buf->str - start)) > 0) ? diff : - diff;
  20. goto done;
  21. }

  22. while(to_move —) //将该login-path之后的login-path整体前移,覆盖move掉的login-path
  23. *(start ++)= *(end ++);

  24. *start= '\0';
  25. file_buf->length -= len;

  26. done:
  27. DBUG_VOID_RETURN;
  28. }

该函数主要是覆盖已经存在的login-path相关的字符串。 函数:dynstr_append(&file_buf, path_buf.str) ,将新添加的login-path内容,添加到file_buf的末尾。

最后来看看最重要,也是最核心的加密函数encrypt_and_write_file的实现:

<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>static int encrypt_and_write_file(DYNAMIC_STRING *file_buf)<br /> </li><li>{<br /></li><li>DBUG_ENTER("encrypt_and_write_file");<br /></li><li>my_bool done= FALSE;<br /></li><li>char cipher[MY_LINE_MAX], *tmp= NULL;<br /></li><li>uint bytes_read=0, len= 0;<br /></li><li>int enc_len= 0; // Can be negative.<br /></li><li><br /></li><li>if (reset_login_file(0) == -1) //清空文件,并重新生成随机加密秘钥,并将对称加密秘钥写入文件头部<br /></li><li>goto error;<br /></li><li>/* Move past key first. */<br /></li><li>if (my_seek(g_fd, MY_LOGIN_HEADER_LEN, SEEK_SET, MYF(MY_WME))<br /></li><li>!= (MY_LOGIN_HEADER_LEN))<br /></li><li>goto error; /* Error while seeking. */<br /></li><li><br /></li><li>tmp= &file_buf->str[bytes_read];<br /></li><li>while(! done)<br /></li><li>{<br /></li><li>len= 0;<br /></li><li><br /></li><li>while(*tmp++ != '\n’) //读取file_buf中的每一行内容<br /></li><li>if (len < (file_buf->length - bytes_read))<br /></li><li>len ++;<br /></li><li>else<br /></li><li>{<br /></li><li>done= TRUE; <br /></li><li>break;<br /></li><li>}<br /></li><li><br /></li><li>if (done)<br /></li><li>break;<br /></li><li><br /></li><li>if ((enc_len= encrypt_buffer(&file_buf->str[bytes_read],++len,cipher+MAX_CIPHER_STORE_LEN))<0) //对读到的这一行内容进行加密,并将密文存放到cipher + MAX_CIPHER_STORE_LEN的地址处</li><li>goto error;<br /></li><li><br /></li><li>bytes_read += len;<br /></li><li><br /></li><li>if (enc_len > MY_LINE_MAX)<br /></li><li>goto error;<br /></li><li><br /></li><li>/* Store cipher length first. */<br /></li><li>int4store(cipher, enc_len); //将密文的长度存放到cipher的头部<br /></li><li><br /></li><li>if ((my_write(g_fd, (const uchar *)cipher, enc_len + MAX_CIPHER_STORE_LEN,<br /></li><li>MYF(MY_WME))) != (enc_len + MAX_CIPHER_STORE_LEN)) //将该行加密过的密文写到文件<br /></li><li>goto error;<br /></li><li>}<br /></li><li>verbose_msg("Successfully written encrypted data to the login file.\n");<br /></li><li>/* Update file_size */<br /></li><li>file_size= bytes_read; //更新文件大小<br /></li><li><br /></li><li>DBUG_RETURN(0);<br /></li><li><br /></li><li>error:<br /></li><li>my_perror("couldn't encrypt the file");<br /></li><li>DBUG_RETURN(-1);<br /></li><li>} </li></ol>
登录后复制
该函数主要功能如下:
  • 读取file_buf中一行
  • 对读取到的行,根据产生的KEY进行加密,将加密后的内容存放到cipher+MAX_CIPHER_STORE_LEN地址处
  • 将密文的长度存放到cipher和cipher+MAX_CIPHER_STORE_LEN之间的地址
  • 将cipher写入文件
  • 更新文件大小
上述1~5一直循环至file_buf中的内容全部加密,并全部写入到文件中为止!
下一节会讲到具体采用的加密算法,并会通过相关的解密算法,编写程序对该文件进行解密操作!!

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/1088144.htmlTechArticleMySQL新特性之mysql_config_editor源码解析 从mysql5.6开始,mysql推出了加密工具mysql_config_editor。在此之前我们通过将账号和密码明文放入my.cnf,从...
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

新报告对传闻中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相机升级进行了严厉的评估 新报告对传闻中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相机升级进行了严厉的评估 Sep 12, 2024 pm 12:23 PM

最近几天,Ice Universe 不断披露有关 Galaxy S25 Ultra 的详细信息,人们普遍认为这款手机将是三星的下一款旗舰智能手机。除此之外,泄密者声称三星只计划升级一款相机

三星 Galaxy S25 Ultra 泄露了第一张渲染图,传闻中的设计变化被曝光 三星 Galaxy S25 Ultra 泄露了第一张渲染图,传闻中的设计变化被曝光 Sep 11, 2024 am 06:37 AM

OnLeaks 现在与 Android Headlines 合作,首次展示了 Galaxy S25 Ultra,几天前,他试图从他的 X(以前的 Twitter)粉丝那里筹集到 4,000 美元以上的资金,但失败了。对于上下文,嵌入在 h 下面的渲染图像

IFA 2024 | TCL 的 NXTPAPER 14 在性能上无法与 Galaxy Tab S10 Ultra 相媲美,但在尺寸上几乎可以与之媲美 IFA 2024 | TCL 的 NXTPAPER 14 在性能上无法与 Galaxy Tab S10 Ultra 相媲美,但在尺寸上几乎可以与之媲美 Sep 07, 2024 am 06:35 AM

除了发布两款新智能手机外,TCL 还发布了一款名为 NXTPAPER 14 的新 Android 平板电脑,其大屏幕尺寸是其卖点之一。 NXTPAPER 14 采用 TCL 标志性品牌哑光液晶面板 3.0 版本

三星 Galaxy S24 FE 预计将以低于预期的价格推出,有四种颜色和两种内存选项 三星 Galaxy S24 FE 预计将以低于预期的价格推出,有四种颜色和两种内存选项 Sep 12, 2024 pm 09:21 PM

三星尚未就何时更新其 Fan Edition (FE) 智能手机系列提供任何提示。目前来看,Galaxy S23 FE 仍然是该公司的最新版本,于 2023 年 10 月年初推出。

Vivo Y300 Pro 在 7.69 毫米纤薄机身中配备 6,500 mAh 电池 Vivo Y300 Pro 在 7.69 毫米纤薄机身中配备 6,500 mAh 电池 Sep 07, 2024 am 06:39 AM

Vivo Y300 Pro刚刚全面亮相,它是最薄的中端Android手机之一,配备大电池。准确来说,这款智能手机的厚度仅为 7.69 毫米,但配备了 6,500 mAh 的电池。这与最近推出的容量相同

新报告对传闻中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相机升级进行了严厉的评估 新报告对传闻中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相机升级进行了严厉的评估 Sep 12, 2024 pm 12:22 PM

最近几天,Ice Universe 不断披露有关 Galaxy S25 Ultra 的详细信息,人们普遍认为这款手机将是三星的下一款旗舰智能手机。除此之外,泄密者声称三星只计划升级一款相机

小米红米 Note 14 Pro Plus 上市,成为首款配备 Light Hunter 800 摄像头的高通 Snapdragon 7s Gen 3 智能手机 小米红米 Note 14 Pro Plus 上市,成为首款配备 Light Hunter 800 摄像头的高通 Snapdragon 7s Gen 3 智能手机 Sep 27, 2024 am 06:23 AM

Redmi Note 14 Pro Plus 现已正式成为去年 Redmi Note 13 Pro Plus 的直接后继产品(亚马逊售价 375 美元)。正如预期的那样,Redmi Note 14 Pro Plus与Redmi Note 14和Redmi Note 14 Pro一起成为Redmi Note 14系列的主角。李

iQOO Z9 Turbo Plus:可能增强的系列旗舰产品已开始预订 iQOO Z9 Turbo Plus:可能增强的系列旗舰产品已开始预订 Sep 10, 2024 am 06:45 AM

OnePlus的姐妹品牌iQOO的2023-4年产品周期可能即将结束;尽管如此,该品牌已宣布 Z9 系列的开发尚未结束。它的最终版,也可能是最高端的 Turbo+ 变体刚刚按照预测发布。时间

See all articles