关于Linux系统中的密码加密流程及原理_VMware, Unix及操作系统讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  VMware, Unix及操作系统讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3166 | 回复: 0   主题: 关于Linux系统中的密码加密流程及原理        下一篇 
    本主题由 Administrator 于 2014-9-9 23:13:30 移动
WilliamLOg
注册用户
等级:新兵
经验:66
发帖:1
精华:0
注册:2014-6-29
状态:离线
发送短消息息给WilliamLOg 加好友    发送短消息息给WilliamLOg 发消息
发表于: IP:您无权察看 2014-9-9 10:41:28 | [全部帖] [楼主帖] 楼主

PAM是个什么东西,词典上没有。

    放狗查了下,这是个简写,全称是:Pluggable Authentication Modules,中文叫“可插入认证模块”。

    它是一种统一的认证方案。PAM 让您能随时改变您的认证方法以及需求,并且不需要重新编译任何代码就封装了所有本地认证方法。具体见 

    PAM 网站

    对于 PAM 您只需要做: 

    对您的密码采用不同于 DES 的加密方式(让它们面对暴力解码(brute-force decode)时更为坚固)。 

    对您所有用户使用资源限额,以防止他们进行拒绝服务(denial-of-service)攻击(进程数、占用内存量等等)。 

    随时启用 shadow password (见下文) 

    只在特定的时间允许特定的用户从特定的地方登录 

    上述介绍来源于

http://man.ddvip.com/linux/Mandrakelinux10server/password-security.html
========================================
root@localhost:~# cat /etc/shadow
root:$1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF.:14838:0:99999:7:::
daemon:*:14838:0:99999:7:::
bin:*:14838:0:99999:7:::
sys:*:14838:0:99999:7:::
sync:*:14838:0:99999:7:::
games:*:14838:0:99999:7:::
man:*:14838:0:99999:7:::
lp:*:14838:0:99999:7:::
mail:*:14838:0:99999:7:::
news:*:14838:0:99999:7:::
uucp:*:14838:0:99999:7:::
proxy:*:14838:0:99999:7:::
www-data:*:14838:0:99999:7:::
backup:*:14838:0:99999:7:::
list:*:14838:0:99999:7:::
irc:*:14838:0:99999:7:::
gnats:*:14838:0:99999:7:::
nobody:*:14838:0:99999:7:::
libuuid:!:14838:0:99999:7:::
Debian-exim:!:14838:0:99999:7:::
statd:*:14838:0:99999:7:::
sshd:*:14838:0:99999:7:::
test::14879:0:99999:7:::


 格式是:

    {用户名}:{加密后的密码字符串}:{口令最后修改时间距1970年1月1日的天数}:{ 口令能被修改之前的天数(防止修改口令,然后立刻将它改回到老口令)}:{口令必须被修改之后的天数}:{口令期满前的天数}:{口令期满后的天数}:{保留}

    shadow是个可读文件,普通用户没有读写权限,超级用户权限为可读写。

    如果密码字符串为*,表示系统用户不能被登入,为!表示用户名被禁用,如果密码字符串为空,表示没有密码,通过passwd -d 用户名 可以清空一个用户的口令。

    具体shadow可参考

shadow how-to


 ,尽管这是一份已经过时了的文档。

    下面探讨下shadow中的密码加密问题:

    还是以上面的root用户为例:

root:$1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF.:14838:0:99999:7:::


 其中的密码域为$1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF. ,参考linux标准的passwd.c源文件,在pw_encrypt函数中可以找到加密方法:

40 char *pw_encrypt (const char *clear, const char *salt)
41 {
      42 static char cipher[128];
      43 char *cp;
      44
      45 cp = crypt (clear, salt);
      46 if (!cp) {
            47
            52 perror ("crypt");
            53 exit (1);
      54 }
      55
      56
      58 if (salt && salt[0] == '$' && strlen (cp) <= 13)
      59 {
            ..........
            79 fprintf (stderr,
            80 _("crypt method not supported by libcrypt? (%s)\n"),
            81 method);
            82 exit (1);
      83 }
      84
      85 if (strlen (cp) != 13)
      86 return cp;
      87 strcpy (cipher, cp);
      88
      89 return cipher;
90 }


 也就是说加密用明文密码和一个叫salt的东西用crypt()加密生成密文。

    再来看看crypt的帮助:

http://www.kernel.org/doc/man-pages/online/pages/man3/crypt.3.html


 可发现原来crypt密文里是由三部分组成的,即:$

salt
encrypted


 目前常用的是当id为1时,使用md5加密,id为5,采用SHA256进行加密,id为6采用SHA512进行加密。

    分析上面的函数,可看出我们的shadow密码中,直接把$

salt
encrypted


 当做salt参数带入进行crypt加密。

    那好,我们可以写个简短的代码进行试验:

#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
if(argc < 2)
printf("no usrname input");
return 1;
if (geteuid() != 0)
fprintf(stderr, "must be setuid root");
struct passwd *pwd;
pwd = getpwnam(argv[1]);
if(pwd ==NULL)
printf("no username found.\n");
else
printf("passwd: %s\n", pwd->pw_passwd);
if(strcmp(pwd->pw_passwd, "x") == 0)
printf("shadow used.\n");
struct spwd *shd= getspnam(argv[1]);
if(shd != NULL)
static char crypt_char[80];
strcpy(crypt_char, shd->sp_pwdp);
char salt[13];
int i=0,j=0;
while(shd->sp_pwdp[i]!='\0'){
salt[i]=shd->sp_pwdp[i];
if(salt[i]=='$'){
j++;
if(j==3){
salt[i+1]='\0';
break;
i++;
if(j<3)perror("file error or user cannot use.");
if(argc==3)
printf("salt: %s, crypt: %s\n", salt, crypt(argv[2], salt));
printf("shadowd passwd: %s\n", shd->sp_pwdp);
return 0;


 保存后执行gcc passwd.c -lcrypt -o passwd

    编译成功后运行./passwd root 123

    其中./passwd是生成的命令,root是我们用来测试的账户,123是测试系统中root用户的密码,执行的结果是:

passwd: x
shadow used.
salt: $1$Bg1H/4mz$, crypt: $1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF.
shadowd passwd: $1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF.


 可见,我们得到了和系统shadow文件下相同结果的密文。

    根据我们的运行结果我们可以看到,在root用户的shadow中,他的salt是$1$Bg1H/4mz$

    我们之前也是用这个salt来进行加密匹配的。但是,问题是:这个salt到底是怎么来的??

    还是分析标准的passwd.c,

    在passwd.c中,找到了生成salt的函数:crypt_make_salt

201 char *crypt_make_salt (const char *meth, void *arg)
202 {
      203
      209 static char result[40];
      210 size_t salt_len = 8;
      211 const char *method;
      212
      213 result[0] = '\0';
      214
      215 if (NULL != meth)
      216 method = meth;
      217 else {
            218 if ((method = getdef_str ("ENCRYPT_METHOD")) == NULL)
            219 method = getdef_bool ("MD5_CRYPT_ENAB") ? "MD5" : "DES";
      220 }
      221
      222 if (!strcmp (method, "MD5")) {
            223 MAGNUM(result, '1');
            224 #ifdef USE_SHA_CRYPT
      225 } else if (!strcmp (method, "SHA256")) {
            226 MAGNUM(result, '5');
            227 strcat(result, SHA_salt_rounds((int *)arg));
            228 salt_len = SHA_salt_size();
      229 } else if (!strcmp (method, "SHA512")) {
            230 MAGNUM(result, '6');
            231 strcat(result, SHA_salt_rounds((int *)arg));
            232 salt_len = SHA_salt_size();
            233 #endif
      234 } else if (0 != strcmp (method, "DES")) {
            235 fprintf (stderr,
            236 _("Invalid ENCRYPT_METHOD value: '%s'.\n"
            237 "Defaulting to DES.\n"),
            238 method);
            239 result[0] = '\0';
      240 }
      241
      242
      245 assert (sizeof (result) > strlen (result) + salt_len);
      246 strncat (result, gensalt (salt_len),
      247 sizeof (result) - strlen (result) - 1);
      248
      249 return result;
250 }


 除了一大段条件判断语句,其实最重要的只有一句gensalt(salt_len)。

    看看gensalt的定义:

167
168 static char *gensalt (unsigned int salt_size)
169 {
      170 static char salt[32];
      171
      172 salt[0] = '\0';
      173
      174 assert (salt_size >= MIN_SALT_SIZE &&
      175 salt_size <= MAX_SALT_SIZE);
      176 seedRNG ();
      177 strcat (salt, l64a (random()));
      178 do {
            179 strcat (salt, l64a (random()));
      180 } while (strlen (salt) < salt_size);
      181 salt[salt_size] = '\0';
      182
      183 return salt;
184 }


 原来神秘的salt只是某个的固定长度的随机的可见的字符串

    每次改写密码时,都会再随机生成一个这样的salt。而用户登入时,会拿用户登入的明文密码经过上述演示的步骤生成密文后和shadow里的密码域进行比较。

    描述:开始的$1$位为加密标志,后面8位12345678为加密使用的salt,后面的为hash 

    加密算法:2000次循环调用MD5加密 

    系统:SHA-512(Unix) 例子:

$6$12345678$U6Yv5E1lWn6mEESzKen42o6rbEm


 说明:Linux或者其他linux内核系统中 长度: 13 个字符 描述:开始的$6$位为加密标志,后面8位为salt,后面的为hash 加密算法:5000次的SHA-512加密 

    系统:SHA-256(Unix) 

$5$12345678$jBWLgeYZbSvREnuBr5s3gp13vqi


 说明:Linux或者其他linux内核系统中 

    长度: 55 个字符 

    描述:开始的$5$位为加密标志,后面8位为salt,后面的为hash 

    加密算法:5000次的SHA-256加密 

    系统:MD5(APR) 

$apr1$12345678$auQSX8Mvzt.tdBi4y6Xgj.


 说明:Linux或者其他linux内核系统中 

    长度:37个字符 

    描述:开始的$apr1$位为加密标志,后面8位为salt,后面的为hash 

    加密算法:2000次循环调用MD5加密 

-----------------windows------------------------------------------


 系统:windows 

Admin:b474d48cdfc4974d86ef4d24904cdd91


 长度:98个字符 

    加密算法:MD4(MD4(Unicode($pass)).Unicode(strtolower($username))) 

------------------mysql--------------------------------------------


 系统:mysql 

606717496665bcba


 说明:老版本的MySql中 

    长度:8字节(16个字符) 

    说明:包括两个字节,且每个字的值不超过0x7fffffff 

    系统:MySQL5 

*E6CC90B878B948C35E92B003C792C46C58C4AF40


 说明:较新版本的MySQL 

    长度:20字节(40位) 

    加密算法:SHA-1(SHA-1($pass)) 

    ------------------其他系统--------------------------------------------- 

    系统:MD5(WordPress) 

$P$B123456780BhGFYSlUqGyE6ErKErL01


 说明:WordPress使用的md5 

    长度:34个字符 

    描述:$P$表示加密类型,然后跟着一位字符,经常是字符‘B’,后面是8位salt,后面是就是hash 

    加密算法:8192次md5循环加密 

    长度:34个字符 

    描述:开始的$H$为加密标志,后面跟着一个字符,一般的都是字符‘9’,然后是8位salt,然后是hash 值

    加密算法:2048次循环调用MD5加密 

    系统:RAdmin v2.x 

    说明:Remote Administrator v2.x版本中 

5e32cceaafed5cc80866737dfb212d7f


 长度:16字节(32个字符) 

    加密算法:字符用0填充到100字节后,将填充过后的字符经过md5加密得到(32位值) 

    ------------------------md5加密-------------------------------------------- 

    标准MD5 

c4ca4238a0b923820dcc509a6f75849b


 使用范围:phpBB v2.x, Joomla 的 1.0.13版本前,及其他cmd 

    长度:16个字符 

    其他的加salt及变形类似: 

md5($pass.$salt)
6f04f0d75f6870858bae14ac0b6d9f73:1234
md5($salt.$pass)
f190ce9ac8445d249747cab7be43f7d5:12
md5(md5($pass))
28c8edde3d61a0411511d3b1866f0636
md5(md5($pass).$salt)
6011527690eddca23580955c216b1fd2:wQ6
md5(md5($salt).md5($pass))
81f87275dd805aa018df8befe09fe9f8:wH6_S
md5(md5($salt).$pass)
816a14db44578f516cbaef25bd8d8296:1234
md5($salt.$pass.$salt)
a3bc9e11fddf4fef4deea11e33668eab:1234
md5($salt.md5($salt.$pass))
1d715e52285e5a6b546e442792652c8a:1234


 $1开头为MD5

    $5开头为SHA256

    $6开头为SHA512

    DES和明文开头无标记

该贴由system转至本版2014-9-9 23:13:30




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