Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2034002
  • 博文数量: 369
  • 博客积分: 10093
  • 博客等级: 上将
  • 技术积分: 4271
  • 用 户 组: 普通用户
  • 注册时间: 2005-03-21 00:59
文章分类

全部博文(369)

文章存档

2013年(1)

2011年(2)

2010年(10)

2009年(16)

2008年(33)

2007年(146)

2006年(160)

2005年(1)

分类: LINUX

2006-03-20 17:44:20

今天研究了一下login程序的实现,其实也没有什么好研究的。整个程序的工作流程就是:
  1. 显示登陆提示符Login:,等待用户输入用户名。
  2. 用户输入用户名之后,显示输入密码的提示符Password:这个时候将终端的回显关掉,就是说用户输入的信息不再同步输出到屏幕上,和图形界面下输入密码时显示为×的功能时一样的,就是为了保护用户输入的密码不被人看到。
  3. 将用户输入的用户名和经过加密后的密码于存放在/etc/password(如果打开了shadow功能密码存放在/etc/shadow中)进行比较,如果相符,登陆成功,如果不相符,登陆失败。
整个过程就是如此简单。这个里面值得一提的就是怎么加密用户的密码的,原来这个程序调用了标准库里面的一个函数crypt:

NAME
       crypt - password and data encryption

SYNOPSIS
       #define _XOPEN_SOURCE
       #include

       char *crypt(const char *key, const char *salt);

crypt的第一个参数就是要加密的元始数据了,第二个参数salt是选择用何种加密算法,man页中如此解释:
salt  is  a two-character string chosen from the set [a-zA-Z0-9./].  This string is used to perturb the algorithm in one of 4096 different ways.
那么password命令是如何选择加密算法的呢?因为目前搞的是潜入式系统,所以直接看的是busybox中的相应程序的代码,发现默认这个参数竟然是"$1$$"。就这样尝试着用C语言简单的写个个程序验证了一下,这样加密出来的密码和已知的密码大不一样,甚至连长度都不一样。肯定是哪里出了问题。继续找资料,最后还是在crypt函数的man页中知道到了答案:
GNU EXTENSION
       The  glibc2  version  of  this  function has the following additional features.  If salt is a character string starting with the three characters "$1$" followed by at most eight  characters,  and  optionally terminated  by  "$",  then instead of using the DES machine, the glibc crypt function uses an MD5-based algorithm, and outputs up to 34 bytes, namely "$1$$", where "" stands for the up  to  8 characters  following  "$1$"  in the salt, followed by 22 bytes chosen from the set [a-zA-Z0-9./].  The entire key is significant here (instead of only the first 8 bytes).

似乎满天的云彩都散了!GNU/Linux默认用的就是crypt的GNU扩展模式,用的是MD5加密算法。当用password程序为用户加密密码时,首先随机生成一个八位的字符串,然后前后加上分隔符作为salt传给crypt。这样生成的密码的前缀就是原来的salt,后面接着是22位MD5加密后的密码,这样大大加强了密码的强度。login进行密码验证时用如下方式进行:
if(strcmp(encryt_passwd, crypt(user_input, encrypt_passwd)) == 0){
 goto: login_ok;
}else{
 goto: login_failed;
}
以下是用perl语言实现的模仿passwd程序生成加密密码的脚本:
#!/usr/bin/perl
#

use strict;
use warnings;

sub get_salt {
        my $valid_chars = "abcdefghijklmnopqrstuvwxyz"
                . "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                . "0123456789"
                . "./";
        my $ret;

        foreach (0..7){
                $ret .= substr($valid_chars, int(rand(length($valid_chars))), 1);
        }

        return $ret;
}

# Get the password from STDIN.
sub get_passwd {
        my $pass;
        my $repass;
        system("stty -echo");
        print "Please input your password: ";
        $pass = ;
        print "\nReinput your password for conform: ";
        $repass = ;
        if($pass ne $repass){
                print "\nThe passwords do not match.\n";
                system("stty echo");
                return "";
        }
        system("stty echo");
# method 1:
#       if($pass  =~ /(.*)\n/){
#               $pass = $1;
#       }
# method 2:
#       ($pass, ) = ($pass =~ /(.*)\n/);
# method 3:
#       ($pass, ) = split "\n", $pass;
# method 4:
        chomp($pass);
        print "\n";
        return $pass;
}

while(1){
        my $passwd = get_passwd;
        if($passwd ne ""){
                my $salt = get_salt;
                $salt = "\$1\$$salt\$";
                print crypt($passwd, $salt) . "\n";
                last;
        }
}

阅读(3654) | 评论(3) | 转发(0) |
给主人留下些什么吧!~~