|
用户名:sagely 笔名:sagely 地区: 行业:其他 |
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
专注于信息安全 QQ:335957600 E_Mail:sagely_zou@163.com
我的blog搬家了
新地址为http://blog.csdn.net/sagely,欢迎大家继续访问.
shell编程
终于完成了一个CA的搭建
前几天整了一个linux服务器,这回就真正可以搭建一个网站了,虽然前面把这些都说得比较详细了,但是中间也出了不少问题。
首先就是openldap出问题,安装openldap是个很麻烦的事情,老是出现数据库不匹配的问题,上网找了找有人说把openldap下的include和lib复制到/usr/include和/usr/lib下面就能解决问题,可是好象更不行,最后还替换了几个文件,这回我想死定了。openldap不装那证书就没地方放。最后我一发狠就把以前装的openldap复制到这个服务器上,居然能用,真是激动。。。所以建议以后大家openldap安装不上就直接复制一个(我也不知道用不用安那个什么数据库),还有就是openldap数据要经常备份,我昨天非法远程断线以后居然openldap就不能启动了,只好把openldap-data全部替换了。
第二就是中文化问题,在linux下不要太相信setlocale,尽量用inconv。反正这个问题让我搞了一两天。还有就是不知道为什么在CGI中变量使用UTF8编码老是出错,所以变量还是用GB2312比较好,到了下一页面再进行处理。
当然还有很多配置问题,太细小了,很麻烦,哎,这里就不想回顾了, 反正思路比较清晰,按照步骤来才是最好的。否则就有好累的拉。
linux下字符集编码转换轻松实现
(1) iconv_t iconv_open(const char *tocode, const char *fromcode);
此函数说明将要进行哪两种编码的转换,tocode是目标编码,fromcode是原编码,该函数返回一个转换句柄,供以下两个函数使用。
(2) size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t *outbytesleft);
此函数从inbuf中读取字符,转换后输出到outbuf中,inbytesleft用以记录还未转换的字符数,outbytesleft用以记录输出缓冲的剩余空间。 (3) int iconv_close(iconv_t cd);
此函数用于关闭转换句柄,释放资源。
例子1: 用C语言实现的转换示例程序
/* f.c : 代码转换示例C程序 */
#include <iconv.h>
#define OUTLEN 255
main()
{
char *in_utf8 = "姝e?ㄥ??瑁?";
char *in_gb2312 = "正在安装";
char out[OUTLEN];
//unicode码转为gb2312码
rc = u2g(in_utf8,strlen(in_utf8),out,OUTLEN);
printf("unicode-->gb2312 out=%sn",out);
//gb2312码转为unicode码
rc = g2u(in_gb2312,strlen(in_gb2312),out,OUTLEN);
printf("gb2312-->unicode out=%sn",out);
}
//代码转换:从一种编码转为另一种编码
int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen)
{
iconv_t cd;
int rc;
char **pin = &inbuf;
char **pout = &outbuf;
cd = iconv_open(to_charset,from_charset);
if (cd==0) return -1;
memset(outbuf,0,outlen);
if (iconv(cd,pin,&inlen,pout,&outlen)==-1) return -1;
iconv_close(cd);
return 0;
}
//UNICODE码转为GB2312码
int u2g(char *inbuf,int inlen,char *outbuf,int outlen)
{
return code_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);
}
//GB2312码转为UNICODE码
int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen)
{
return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}
例子2: 用C++语言实现的转换示例程序
/* f.cpp : 代码转换示例C++程序 */
#include <iconv.h>
#include <iostream>
#define OUTLEN 255
using namespace std;
// 代码转换操作类
class CodeConverter {
private:
iconv_t cd;
public:
// 构造
CodeConverter(const char *from_charset,const char *to_charset) {
cd = iconv_open(to_charset,from_charset);
}
// 析构
~CodeConverter() {
iconv_close(cd);
}
// 转换输出
int convert(char *inbuf,int inlen,char *outbuf,int outlen) {
char **pin = &inbuf;
char **pout = &outbuf;
memset(outbuf,0,outlen);
return iconv(cd,pin,(size_t *)&inlen,pout,(size_t *)&outlen);
}
};
int main(int argc, char **argv)
{
char *in_utf8 = "姝e?ㄥ??瑁?";
char *in_gb2312 = "正在安装";
char out[OUTLEN];
// utf-8-->gb2312
CodeConverter cc = CodeConverter("utf-8","gb2312");
cc.convert(in_utf8,strlen(in_utf8),out,OUTLEN);
cout << "utf-8-->gb2312 in=" << in_utf8 << ",out=" << out << endl;
// gb2312-->utf-8
CodeConverter cc2 = CodeConverter("gb2312","utf-8");
cc2.convert(in_gb2312,strlen(in_gb2312),out,OUTLEN);
cout << "gb2312-->utf-8 in=" << in_gb2312 << ",out=" << out << endl;
}
二、利用iconv命令进行编码转换
iconv命令用于转换指定文件的编码,默认输出到标准输出设备,亦可指定输出文件。
用法: iconv [选项...] [文件...]
有如下选项可用:
输入/输出格式规范:
-f, --from-code=名称 原始文本编码
-t, --to-code=名称 输出编码
信息:
-l, --list 列举所有已知的字符集
输出控制:
-c 从输出中忽略无效的字符
-o, --output=FILE 输出文件
-s, --silent 关闭警告
--verbose 打印进度信息
-?, --help 给出该系统求助列表
--usage 给出简要的用法信息
-V, --version 打印程序版本号
例子:
iconv -f utf-8 -t gb2312 aaa.txt >bbb.txt
这个命令读取aaa.txt文件,从utf-8编码转换为gb2312编码,其输出定向到bbb.txt文件。
小结: LINUX为我们提供了强大的编码转换工具,给我们带来了方便。
应用地址:http://www.donews.net/xzwenlan/archive/2005/02/05/269237.aspx
利用openssl进行RSA加密签名小结
加密(签名)的过程是(M的e次方)mod n,在这里我们把消息M假定为一个数字,但实际上消息一般为字符串,所以必须有一个将字符串转化为数字的规则,并且要让这个数字的大小和n相当(也不能比n大)。这样做的目的是为了使(M的e次方)> n ,假如不是这样那么C=(M的e次方)mod n = (M的e次方),也就是mod n完全没有作用,攻击者就能够轻松的通过取C的第e次方根来恢复M。那么下面来讨论这种转换的标准:
1,计算出格式化加密分组所需的大小。如果n是一个L位的数字,那么加密分组就有L/8字节长(只舍不入)。
2,第一个高位字节总是0,而第二个为分组类型。对加密来说,这是2,对签名来说是1,这样就确保形成的数字比n要稍小。
3,消息存放在加密分组的低位字节中,并在之前安放一个0
00 01 ff ff ff ff ... 00 消息数据 —— 这是签名时的转换方式
00 02 伪随机非零字节 00 消息数据 —— 这是加密时的转换方式
由这里可以看出,对一个消息进行重复签名时,签名结果是一样的。对一个消息进行反复加密时,得出来的加密分组是不一样的。恢复加密分组时,就只需要从第三个字节开始一直向右推进到一个0字节为止,这就找到了数据起始位置。
但是需要注意上面这个过程中还要加入摘要算法的标识符,因为:
在RSA_sign函数中在RSA_eay_private_encrypt(i,s,sigret,rsa,RSA_PKCS1_PADDING);函数以前有一段程序,问题的答案就在这里,楼上说的摘要是存在m中的,而s=3020300C06082A864886F70D020505000410+m(34比特),这段程序意思很好理解,就是加上摘要算法的标识符。所以3020300C06082A864886F70D020505000410就是代表md5这个algorithm。
这样我们就可以得出签名的数据的转化格式
00 01 ff ff ff ff ... 00 算法标识 消息数据
那么我们看看openssl中证书签名的过程:
int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md)
{
//先进行ret->cert_info->signature,以及ret->sig_alg的设置;
inl=i2d_X509_CINF(ret->cert_info,NULL);//求出证书编码后的长度
buf_in=(unsigned char *)OPENSSL_malloc((unsigned int)inl);//申请空间
outll=outl=EVP_PKEY_size(pkey1);
buf_outl=(unsigned char *)OPENSSL_malloc((unsigned int)inl);
if ((buf_in == NULL) ││ (buf_outl== NULL))
{
outl=0;
goto err;
}
p=buf_in;//p与buf-in共享一段地址
i2d_X509_CINF(ret->cert_info,&p);//将证书编码存入buf-in
EVP_MD_CTX_init(&ctxl);//初始化
EVP_SignInit(&ctxl,dgst);//将需要使用的摘要算法存入ctxl中
EVP_SignUpdate(&ctxl,(unsigned char *)buf_in,inl);//存入证书的编码值
EVP_DigestFinal(&ctxl,&(m[0]),&m_len);//求取编码的长度为m_len摘要值存入m中
RSA_sign(ctxl->digest->type,m,m_len,buf_out,outl,pkey->pkey.rsa)//求取摘要值的签名值,最后将长度为outl的签名值存入buf-out。
RSA_sign最主要是调用了RSA_eay_private_encrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding)函数。这里值得注意的一点是: RSA_eay_private_encrypt 加密时默认调用RSA密钥文件中的p、q因子使用中国剩余定理的算法进行加密,这样可以提高效率,而不是直接调用pkey->pkey.rsa->d进行加密,所以有时候直接改动pkey->pkey.rsa->d而加密结果是不会变化的。
在此过程中编码函数采用了EME-PKCS1——5-ENCOD编码函数,大数与字符串之间的转换函数使用的是OS2IP、I20SP格式转换函数BN_bin2bn和BN_bn2bin。EME-PKCS1_5-ENCODE 函数
输入:字符串 M 、emlen 表示信息编码以后的长度。(注意:信息M 的长度不得大于 emlen-10 个字节)
输出: EM 表示 M 经过编码以后的内容。函数的具体操作步骤是随机产生 emlen-len(M)-2 字节长度的非零字符串PS ,且len(PS)>=8 然后按照下列方式 EM= 02 ││ PS ││ 00 ││ M 的方式把它们连接起来。
linux启动慢的问题
在运行linux的时候突然挂掉了,毫无反应,觉得真是奇怪,电脑硬件已经不差了, 何况还是linux操作系统,居然也死机?然后重起以后发现进Xwindows特别慢。呵呵不过这个问题我知道怎么办,因为上次我遇见过,具体为什么我也没搞明白,据我推测是开机启动的时候往/tmp目录下入了一个.font-unix文件,这个文件与xfs服务有关,也它与/etc/X11/XFree86Config里面的FontPath "UNIX/:7100"有关系。下面是解决办法:
1:删除/tmp目录下所有文件,在这里有人告诉我说用rm -rf *,我觉得可能还是删除不掉.font-unix文件,不知道有没有效果,我的做法就是
rm -rf /tmp
mkdir /tmp
chmod 777 /tmp
最后一句话很重要,这次我一急就忘记这句话了。马上就造成完全不能进入xwindows,连命令行都登不进去,郁闷透顶。那就只好拿安装盘F4,然后linux rescue,不过需要注意的是,假如要进入真正的目录的话,好象要cd /mnt/sysimage,然后把/tmp权限给改了。但是重启以后发现还是特别慢,那就只能把FontPath "UNIX/:7100" 注释掉,这次重启果然快了,可是过了一天后发现好象没有输入法了,xfs &发现有错误,哎,现在还没解决呢,有谁知道请告诉我,我只好重装个输入法了。
为IE增加按钮
学习使用cryptoapi第三天
windows2003的安装
高级指针话题
2,指向指针的指针,下面分别看几个例子
char string[3]={'c','d','e'}.定义了三个char型的变量string[0]='c',string[1]='d',string[2]='e'.
char *pstring={"cde"},定义了一个字符串,其中string[0]='c',string[1]='d',string[2]='e'.
现在明显可以看出上面两者的联系了。其实string=pstring.
char string[3][3]={'M','o','n';'T','u','e';'W','e','d'};这样string[0][0]='M',,,,,
char *pstring[3]={"Mon","Tue","Wed"},定义了三个char *string型的变量。string[0]="Mon",string[0][0]='M'
char **ppstring.那这个是什么呢,他就是个指向指针的指针,可以直接初始化ppstring=pstring,或者可以ppstring=&(pstring[0]),使用的时候可以完全和*pstring[3]差不多使用了。
所以指向指针的指针也就是多了一个间接访问而已,只要知道了指针就是地址,*就是去访问地址的数据就可以了。
3,函数指针。
int (*f)(),前面一个括号迫使间接访问在函数调用之前,那么就是说访问内存中的某个位置的函数。这就是函数指针的概念。
初始化:int f(int); int (*pf)(inf)=&f;
调用方式:int ans=pf(25);
下面讨论两个具体应用的问题:
1),回调函数
我们先看看下面这段程序:
int comp(int a,int b)
{
if(a==b)return 0;
else return 1;
}
完成的功能实在是简单,就是比较一下两个数是否一致。但是你是否发现这个只能比较int型的数据,要是比较char的呢,那必须得重新写一个函数,比较float也得重新写一个,这样是不是有点麻烦,并且易用性也不好,换一个类型就要换一个函数。那么我们考虑是否在comp的时候不传具体的类型呢,因为我们根本也不知道要传什么类型给comp。解决难题的办法就是把参数类型声明为void *,表示"一个指向未知类型的指针"。然后加一个回调函数作为参数,这样在按照不同的类型编写不同的回调函数,在上层就保证了comp函数的易用性。下面请看改写的函数
int comp(void *a,void *b, int (*compare)(void const *,void const *))
{
if(compare(a,b))return 1;
else return 0;
}
int compare_int(void const *a,void const *b)
{
if(*(int*)a==*(int*)b) return 0;
else return 1;
}
int compare_char(void const *a,void const *b)
{
if(*(char*)a==*(char*)b) return 0;
else return 1;
}
在主函数中可以这样调用
int a=2;int b=2;
comp(&a,&b,compare_int);
char c='d';char d='d';
comp(&d,&c,compare_char);
现在在C++中已经有重载和模板的技术了,上面的任务根本不用这么麻烦实现的。但是openssl是用C语言写的,里面大量的void类型,并且大量的指向函数的指针,希望这点讲解对大家看openssl能有点帮助。
2),转移表
我们下面看个例子,在一个计算器的例子中,有如下一些语句:
switch(oper)
case ADD:
result=add(op1,op2);
break;
case SUB:
result=sub(op1,op2);
break;
case MUL:
result=mul(op1,op2);
break;
case DIV:
result=div(op1,op2);
break;
...
对于一个功能复杂的计算器,那么switch语句将非常长。为了使用switch语句,表示操作符的代码必须是整数。如果它们是从零开始连续的整数,我们可以使用转换表来完成这个任务。转换表就是一个函数指针数组。
创建一个转换表需要两个步骤。首先,声明并初始化一个函数指针数组。唯一需要留心之处就是确保这些函数的原形出现在这个数组的声明之前。
double add(double,double);
double sub(double,double);
double mul(double,double);
...
double (*oper_func[])(double,double)={add,sub,mul,div,...};
初始化列表中各个函数名的正确顺序取决于程序中用于表示每个操作符的整型代码。这个例子假定ADD是0,SUB是1,MUL是3,,,
第2个步骤是用下面语句替换前面整条switch语句:
result=oper_func[oper](op1,op2);
oper从数组中选择正确的函数指针,而函数调用操作符将执行这个函数。