惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hacker News: Ask HN
Hacker News: Ask HN
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog RSS Feed
Jina AI
Jina AI
Stack Overflow Blog
Stack Overflow Blog
量子位
博客园_首页
Vercel News
Vercel News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Forbes - Security
Forbes - Security
IT之家
IT之家
N
News and Events Feed by Topic
S
Security Affairs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Webroot Blog
Webroot Blog
Recorded Future
Recorded Future
L
LangChain Blog
Y
Y Combinator Blog
AI
AI
MyScale Blog
MyScale Blog
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Know Your Adversary
Know Your Adversary
AWS News Blog
AWS News Blog
Help Net Security
Help Net Security
Cyberwarzone
Cyberwarzone
L
Lohrmann on Cybersecurity
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google Online Security Blog
Google Online Security Blog
V2EX - 技术
V2EX - 技术
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
PCI Perspectives
PCI Perspectives
I
Intezer
T
Tenable Blog
G
Google Developers Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Troy Hunt's Blog
L
LINUX DO - 最新话题
云风的 BLOG
云风的 BLOG
C
CXSECURITY Database RSS Feed - CXSecurity.com
有赞技术团队
有赞技术团队
O
OpenAI News
P
Proofpoint News Feed
TaoSecurity Blog
TaoSecurity Blog
C
Check Point Blog
Last Week in AI
Last Week in AI
S
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
Blog — PlanetScale
Blog — PlanetScale

博客园 - refuly

【半原创】将js和css文件装入localStorage加速程序执行 SqlAgent备份脚本 ASP.net 使用HttpHandler实现图片防盗链 提取HTML代码中文字的C#函数 - refuly - 博客园 水晶头的制作 解决ASP.NET“类型初始值设定项引发异常” 解决vs2005 经WebDeployment发布后 global.asax 事件不启动 C# 实现Epson热敏打印机打印 Pos机用 去掉文件名中的非法字符 - refuly - 博客园 window.onbeforeunload与window.onunlad对比 用Response.Filter生成静态页[要注意并发问题] HttpModule通过修改CSS切换皮肤 asp.net Excel导入&导出 - refuly - 博客园 计算机端口的介绍 Sql Server数据导出EXCEL 获取字符串的真实长度 c# 小数位数处理 C#进制转换 Asp.net 备份、还原Ms SQLServer及压缩Access数据库
新旧身份证合法性验证及验证算法
refuly · 2009-04-11 · via 博客园 - refuly

    以前浏览网站时,偶尔会发现有些网站注册时需要填写身份证,而且对身份证检验相当严格,猜想必定存在某种算法。今天恰好有空,上网找了一下,有些收获,不敢独享,现与众网友共享。本人已将算法用C#实现,希望大家能多多指点。

1.         中国公民身份证常识:

我国现行使用公民身份证号码有两种尊循两个国家标准,〖GB 11643-1989〗和〖GB 11643-1999〗。

GB 11643-1989〗中规定的是15位身份证号码:排列顺序从左至右依次为:六位数字地址码,六位数字出生日期码,三位数字顺序码,其中出生日期码不包含世纪数。

       GB 11643-1999〗中规定的是18位身份证号码:公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。

6位行政区划分代码

6位出生日期

3位顺序码

1位校验码

       行政区划分代码:表示编码对象常住户口所在县(市、旗、区)的行政区划代码。

       行政区划分代码国家标准GB T 2260-1999

       出生日期码:表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。

       顺序码:表示同一地址码所标识的区域范围内,对同年、同月、同日出生的人员编定的顺序号。顺序码的奇数分给男性,偶数分给女性。

    校验码:是根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2校验码计算出来的检验码。

2.         算法

关于身份证号码最后一位的校验码的算法如下:

假设最后一位的校验码为R

C=(a[i]*w[i])%11 (i=2,3,…,18)

其中∑:表示求和

i:表示身份证号码每一位的序号,从右至左,最左侧为18,最右侧位1

*:表示乘号

a[i]:表示身份证号码第i位上的号码

w[i]:表示第i位上的权值,计算方法:w[i]=2^(i-1)%11

%:表示求模运算

^:表示求幂运算

经过上述方法得到的C的范围在0~10之间,它与身份证最后一位校验位的对应规则为:

C

0

1

2

3

4

5

6

7

8

9

10

R

1

0

X

9

8

7

6

5

4

3

2

由此看出 X 就是 10,罗马数字中的 10 就是X,所以在新标准的身份证号码中可能含有非数字的字母X

3.         C#实现

using System;
using
 System.Collections.Generic;
using
 System.Text;namespace Zwf.IdCard
{
    
public class
 Check
    {
        
//位权值数组

        private static byte[] Weight = new byte[17];
        
//身份证行政区划代码部分长度

        private static byte fPart = 6;
        
//算法求模关键参数

        private static byte fMode = 11;
        
//旧身份证长度

        private static byte oIdLen = 15;
        
//新身份证长度

        private static byte nIdLen = 18;
        
//新身份证年份标记值

        private static string yearFlag = "19";
        
//校验字符串

        private static string checkCode = "10X98765432";
        
//最小行政区划分代码

        private static int minCode = 110000;
        
//最大行政区划分代码

        private static int maxCode = 820000;
        
private static Random rand = new
 Random();/// <summary>
        
/// 计算位权值数组
        
/// </summary>

        private static void SetWBuffer()
        {
            
for (int i = 0; i < Weight.Length; i++
)
            {
                
int k = (int)Math.Pow(2, (Weight.Length -
 i));
                Weight[i] 
= (byte)(k %
 fMode);
            }
        }
/// <summary>

        
/// 获取新身份证最后一位校验位
        
/// </summary>

        
/// <param name="idCard">身份证号码</param>
        
/// <returns></returns>
        private static string GetCheckCode(string idCard)
        {
            
int sum = 0
;
            
///进行加权求和计算

            for (int i = 0; i < Weight.Length; i++)
            {
                sum 
+= int.Parse(idCard.Substring(i, 1)) *
 Weight[i];
            }
            
///求模运算得到模值

            byte mode = (byte)(sum % fMode);
            
return checkCode.Substring(mode, 1
);
        }
/// <summary>

        
/// 检查身份证长度是否合法
        
/// </summary>

        
/// <param name="idCard">身份证号码</param>
        
/// <returns></returns>
        private static bool CheckLen(string idCard)
        {
            
if (idCard.Length == oIdLen || idCard.Length ==
 nIdLen)
            {
                
return true
;
            }
            
return false
;
        }
/// <summary>

        
/// 验证是否是新身份证
        
/// </summary>

        
/// <param name="idCard">身份证号码</param>
        
/// <returns></returns>
        private static bool IsNew(string idCard)
        {
            
if (idCard.Length ==
 nIdLen)
            {
                
return true
;
            }
            
return false
;
        }
/// <summary>

        
/// 获取时间串
        
/// </summary>

        
/// <param name="idCard">身份证号码</param>
        
/// <returns></returns>
        private static string GetDate(string idCard)
        {
            
string str = ""
;
            
if
 (IsNew(idCard))
            {
                str 
= idCard.Substring(fPart, 8
);
            }
            
else

            {
                str 
= yearFlag + idCard.Substring(fPart, 6);
            }
            
return
 str;
        }
/// <summary>

        
/// 检查时间是否合法
        
/// </summary>

        
/// <param name="idCard"></param>
        
/// <returns></returns>
        private static bool CheckDate(string idCard)
        {
            
//日期是否符合格式

            bool flag = false;
            
string strDate =
 GetDate(idCard);int year = Convert.ToInt32(strDate.Substring(04));
            
int month = Convert.ToInt32(strDate.Substring(42
));
            
int day = Convert.ToInt32(strDate.Substring(62
));///年份是否合法,本例暂定年份在1900-1999之间为合法年份
            if ((year > 1900&& (year < 2999))
            {
                flag 
= true
;
            }
            
else

            {
                flag 
= false;
            }
///检查月份是否合法

            if ((month >= 1&& (month <= 12))
            {
                flag 
= true
;
            }
            
else

            {
                flag 
= false;
            }
///检查天是否合法,本例以农历为准

            if ((day >= 1&& (day <= 30))
            {
                flag 
= true
;
            }
            
else

            {
                flag 
= false;
            }
            
return
 flag;
        }
/// <summary>

        
/// 根据年份和月份检查天是否合法
        
/// </summary>

        
/// <param name="year">年份</param>
        
/// <param name="month">月份</param>
        
/// <param name="day"></param>
        
/// <returns></returns>
        private static bool CheckDay(int year, int month, int day)
        {
            
///是否是闰年

            bool rYearFlag = false;
            
///天是否合法

            bool rDayFlag = false;
            
if (((year % 4 == 0&& (year % 3200 != 0)) || (year % 400 == 0
))
            {
                rYearFlag 
= true
;
            }
#region 检查天是否合法

            
if (month == 2)
            {
                
if
 (rYearFlag)
                {
                    
if (day > 0 && day <= 29
)
                    {
                        rDayFlag 
= true
;
                    }
                }
                
else

                {
                    
if (day > 0 && day <= 28)
                    {
                        rDayFlag 
= true
;
                    }
                }
            }
            
else if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12
)
            {
                
if (day > 0 && day <= 31
)
                {
                    rDayFlag 
= true
;
                }
            }
            
else

            {
                
if (day > 0 && day <= 30)
                {
                    rDayFlag 
= true
;
                }
            }
            
#endregion
return rDayFlag;
        }
/// <summary>

        
/// 检查身份证是否合法
        
/// </summary>

        
/// <param name="idCard"></param>
        
/// <returns></returns>
        public static bool CheckCard(string idCard, out string msg)
        {
            
///身份证是否合法标志

            bool flag = false;
            msg 
= string
.Empty;
            SetWBuffer();
            
if (!
CheckLen(idCard))
            {
                msg 
= "身份证长度不符合要求"
;
                flag 
= false
;
            }
            
else

            {
                
if (!CheckDate(idCard))
                {
                    msg 
= "身份证日期不符合要求"
;
                    flag 
= false
;
                }
                
else

                {
                    
if (!IsNew(idCard))
                    {
                        idCard 
=
 GetNewIdCard(idCard);
                    }
                    
string checkCode =
 GetCheckCode(idCard);
                    
string lastCode = idCard.Substring(idCard.Length - 11
);
                    
if (checkCode ==
 lastCode)
                    {
                        flag 
= true
;
                    }
                    
else

                    {
                        msg 
= "身份证验证错误";
                        flag 
= false
;
                    }
                }
            }
            
return
 flag;
        }
/// <summary>

        
/// 旧身份证号码转换成新身份证号码
        
/// </summary>

        
/// <param name="oldIdCard">旧身份证号码</param>
        
/// <returns>新身份证号码</returns>
        private static string GetNewIdCard(string oldIdCard)
        {
            
if (oldIdCard.Length == 15
)
            {
                
string newIdCard = oldIdCard.Substring(0
, fPart);
                newIdCard 
+=
 yearFlag;
                newIdCard 
+= oldIdCard.Substring(fPart, 9
);
                newIdCard 
+=
 GetCheckCode(newIdCard);
                
return
 newIdCard;
            }
            
return string
.Empty;
        }
/// <summary>

        
/// 新身份证号码转换成旧身份证号码
        
/// </summary>

        
/// <param name="newIdCard">新身份证号码</param>
        
/// <returns>旧身份证号码</returns>
        private static string GetOldIdCard(string newIdCard)
        {
            
if (newIdCard.Length == 18
)
            {
                
string oldIdCard = newIdCard.Substring(0
, fPart);
                oldIdCard 
+= newIdCard.Substring(89
);
                
return
 oldIdCard;
            }
            
return string
.Empty;
        }
    }
}

我们可以直接执行方法Zwf.IdCard.Check.CheckCard(身份证号码)进行验证身份证是否正确

该方法返回true表示身份证号码合法,false表示身份证号码不合法。

写得比较粗糙,还望各位高人多指点。

4.         参考资料

"将15位身份证转换为18位身份证":http://www.joyblog.cn/article.asp?id=105