身份证的加密与压缩思路与实现
2019独角兽企业重金招聘Python工程师标准>>>
假设场景:假设将身份证号应用于数据库主键,但要满足两方面要求:1.不能明文存储。2.压缩长度。
(一)身份证的规则
目前我国身份证是18位按一定规则生成的字符串。其生成规则如下:
数字地址码(6) + 数字出生日期码(8) + 数字顺序码(3) + 数字校验码(1)
地址码:表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260的规定执行。
出生日期码:表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符。
顺序码:表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。
校验码:
(1)十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和
Ai:表示第i位置上的身份证号码数字值 Wi:表示第i位置上的加权因子
Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4
(2)计算模 Y = mod(S, 11) , Y取值: 0 1 2 3 4 5 6 7 8 9 10
(3)通过模得到对应的校验码: 1 0 X 9 8 7 6 5 4 3 2
(二)身份证检验
按上述规范编写的身份证检验逻辑,可以参考最后的代码。
(三)身份证加密与压缩
基本思路:将身份证按一定规律拆解,然后按一定的计算方式进行换算。拆解方式如下:
城市(2)+地址(4)+年份(4)+月份(2)+天(2)+顺序号(3)+校验码(1)
(1)将城市和校验码的对应关系打乱后转换成36进制字符。
(2)地址、月份、天、顺序号直接转化成36进制字符。当然也可以加一点点的其它运算。另外还可以适当地进行位数的压缩。如月份取值:1-12,在36进制的情况下,一位字符即可。
(3)年份-固定一个年份(如:1800),将结果转化成36进制。这里采用2位36进制保存,可以支持使用1295年了。
最后生成的结果组成方式如下, 一共13位字符:
城市(2)+地址(4)+年份(2)+月份(1)+天(1)+顺序码(2)+校验码(1)
(四)示例代码
package com.zheng.coderepo.idcard;import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Calendar;/**
* Created by zhangchaozheng on 17-2-21.
*/
public class IdCardUtils {/*** 省、直辖市代码表*/public static final String cityCode[] = {"11", "12", "13", "14", "15", "21", "22", "23", "31", "32", "33", "34", "35", "36", "37", "41","42", "43", "44", "45", "46", "50", "51", "52", "53", "54", "61", "62", "63", "64", "65", "71","81", "82", "91"};/*** 每位加权因子*/public static final int Wi[] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};/*** 第18位校检码*/public static final String ValCodeArr[] = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};/*** 省、直辖市代码表*/public static final String cityCode_encrypt[] = {"15", "16", "17", "18", "19", "20", "99", "23", "24", "01", "02", "03", "44", "45", "46", "47","48", "49", "61", "62", "63", "95", "96", "97", "64", "67", "68", "69", "51", "52", "53", "54","55", "56", "88"};/*** 第18位校检码*/public static final String ValCodeArr_encrypt[] = {"5", "8", "4", "1", "2", "3", "7", "12", "13", "15", "21"};private static final int FROM_YEAR = 1800;/*** 检查身份证是否合法* @param idNo* @return*/public static boolean checkIdNo(String idNo) {// 1.检查身份证长度if (idNo.length() != 18) {throw new IllegalArgumentException("身份证号码长度应该为18位。");}// 2.检查身份证号是否符合数字规则String Ai = idNo.substring(0, 17);if (StringUtils.isNumeric(Ai) == false) {throw new IllegalArgumentException("18位号码除最后一位外,都应为数字。");}// 3.检查出年日期是否有效String strYear = Ai.substring(6, 10);// 年份String strMonth = Ai.substring(10, 12);// 月份String strDay = Ai.substring(12, 14);// 月份Calendar cal = Calendar.getInstance();int currentYear = cal.get(Calendar.YEAR);int year = Integer.parseInt(strYear);if ((currentYear - year) < 0 || (currentYear - year) > 150) {throw new IllegalArgumentException("身份证出生日期年份无效。");}int month = Integer.parseInt(strMonth);if (month < 0 || month > 12) {throw new IllegalArgumentException("身份证出生日期月份无效。");}int day = Integer.parseInt(strDay);if (day < 0 || day > 31) {throw new IllegalArgumentException("身份证出生日期的天无效。");}SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");sdf.setLenient(false);try {sdf.parse(strYear + strMonth + strDay);} catch (Exception e) {throw new IllegalArgumentException("身份证出生日期无效。");}// 4.地区码是否有效if (!ArrayUtils.contains(cityCode, Ai.substring(0, 2))) {throw new IllegalArgumentException("身份证地区编码错误。");}// 5.验证最后一位校验码int totalAiWi = 0;for (int i = 0; i < 17; i++) {totalAiWi = totalAiWi + Integer.parseInt(String.valueOf(Ai.charAt(i))) * Wi[i];}int modValue = totalAiWi % 11;String strVerifyCode = ValCodeArr[modValue];Ai = Ai + strVerifyCode;if (Ai.equals(idNo) == false) {throw new IllegalArgumentException("身份证无效,不是合法的身份证号码");}return true;}public static String encrypt(String idNo) {//检查证件号的合法性try {checkIdNo(idNo);} catch (Exception e) {return "";}String city = idNo.substring(0, 2);//cityString addr = idNo.substring(2, 6);//addrString year = idNo.substring(6, 10);// 年份String month = idNo.substring(10, 12);// 月份String day = idNo.substring(12, 14);// 月份String seq = idNo.substring(14, 17);//序号String valCode = idNo.substring(17, 18);//检验位String cityChange = new BigInteger(getCityChange(city), 10).toString(36);String addrChange = new BigInteger(addr, 10).toString(36);String yearChange = new BigInteger((Integer.parseInt(year) - FROM_YEAR) + "", 10).toString(36);String monthChange = new BigInteger(month, 10).toString(36);String dayChange = new BigInteger(day, 10).toString(36);String seqChange = new BigInteger(seq, 10).toString(36);String valCodeChange = new BigInteger(getValCodeChange(valCode), 10).toString(36);return "" +//保持2位leftPad(cityChange, 2) +//保持4位leftPad(addrChange, 4) +//保持2位,使用36进制保存可以支持1295年leftPad(yearChange, 2) +//使用1位leftPad(monthChange, 1) +//使用1位leftPad(dayChange, 1) +//保持2位leftPad(seqChange, 2) +//保持1位valCodeChange;}public static String decrypt(String pk) {String city = pk.substring(0, 2);//cityString addr = pk.substring(2, 6);//addrString year = pk.substring(6, 8);// 年份String month = pk.substring(8, 9);// 月份String day = pk.substring(9, 10);// 月份String seq = pk.substring(10, 12);//序号String valCode = pk.substring(12, 13);//检验位//还原2位String cityChange = getRealCity(new BigInteger(city, 36).toString(10));//还原4位String addrChange = new BigInteger(addr, 36).toString(10);//还原4位String yearChange = new BigInteger(year, 36).add(BigInteger.valueOf(FROM_YEAR)).toString(10);//还原2位String monthChange = new BigInteger(month, 36).toString(10);//还原2位String dayChange = new BigInteger(day, 36).toString(10);//还原3位String seqChange = new BigInteger(seq, 36).toString(10);//还原1位String valCodeChange = getRealValCode(new BigInteger(valCode, 36).toString(10));return cityChange +leftPad(addrChange, 4) +leftPad(yearChange, 2) +leftPad(monthChange, 2) +leftPad(dayChange, 2) +leftPad(seqChange, 3) +valCodeChange;}private static String getValCodeChange(String valCode) {int i = ArrayUtils.indexOf(ValCodeArr, valCode);return ValCodeArr_encrypt[i];}private static String getRealValCode(String valCode) {int i = ArrayUtils.indexOf(ValCodeArr_encrypt, valCode);return ValCodeArr[i];}private static String getCityChange(String city) {int i = ArrayUtils.indexOf(cityCode, city);return cityCode_encrypt[i];}private static String getRealCity(String city) {int i = ArrayUtils.indexOf(cityCode_encrypt, city);return cityCode[i];}private static String leftPad(String addrChange, int size) {return StringUtils.leftPad(addrChange, size, "0");}}
转载于:https://my.oschina.net/u/561917/blog/843040
身份证的加密与压缩思路与实现相关推荐
- 如何区分加密、压缩、编码?
原文标题:How to distinguish between encryption, compression, and encoding? 原文作者: M157q 译文出自:云子可信官方论坛 本文永 ...
- PC版微信加密图片解密思路与代码实现_Python
PC版微信加密图片解密思路与代码实现_Python 前言 PC版的微信会加密存储用户接受到的所有图片信息. 存储路径为 C:\Users\用户名\Documents\WeChat Files\微信号\ ...
- 保护你的聊天隐私---“外挂式”加密软件设计思路
保护你的聊天隐私---"外挂式"加密软件设计思路<?xml:namespace prefix = o /> Jack zhai 即时通讯工具(常用的是聊天软件与网上电话 ...
- 数据库身份证号加密密码加密_使用基于密码的加密保护会议室数据库
数据库身份证号加密密码加密 As developers we are often tasked with securing the data we store in our applications. ...
- 如何给U盘,SD卡加密(压缩加密与veracrypt加密)
如何给U盘,SD卡之类的存贮设备加密? 如果你已经是Windows专业版,那么不用看本篇教程 可以直接用bitlocker加密... 但是对于我这样家庭版的用户来说,还有两种方法 压缩文件加密 通过软 ...
- 对手机号与身份证号加密显示
接到个需求需要对传过来的手机号与身份证号加密显示,如图所示 忘了之前从哪里copy了一份代码了(侵删),怕以后需要留个记录 function encryptionInfo(val) {var oldV ...
- 数据库身份证号加密密码加密_使用密码加密数据
数据库身份证号加密密码加密 介绍 (Introduction) When we're encrypting data, typically we will create a random key th ...
- 关于实现手机号,身份证号加密解密解决方案
关于实现手机号,身份证号加密解密解决方案 要求: 1.不入侵任何业务逻辑 2.可以扩展解密解密字段 3.可以扩展加密解密算法 环境: jdk1.8.springMVC 解决方案: 基于自定义注解和my ...
- vant框架上传组件---上传身份证两面图片需求并且压缩图片质量,非压缩长宽——商城项目
场景 1.vant框架上传组件-上传身份证两面图片需求并且压缩图片质量,非压缩长宽--商城项目 2.压缩图片质量大小-- 3.压缩逻辑因为是正反两面单独压缩执行,所以我这里使用 Promise.all ...
最新文章
- 《预训练周刊》第38期: Transformer、BERT结构优化
- 基于局部均方差相关信息的图像去噪及其在实时磨皮美容算法中的应用
- leetcode 171. Excel表列序号
- 手写“2021”新年春节艺术字,好素材会说话!
- 开发中常用日志搜索技巧
- Spring 4.xx开发环境搭建
- 什么是CANFD Light
- 2021新版OPEN易支付免费开源版 亲测可用
- fastadmin 多表关联查询
- const T vs. T const ——Dan Saks 【翻译】
- MongoDB:shutting down with code:100
- 不用工具,如何快速计算文件的MD5?
- Queue和Deque
- http://mybatis.org/dtd/mybatis-3-mapper.dtd 报红
- 计算机专业英语自学国外教材,计算机专业英语课程 自学辅导方案精选.pdf
- 笔记dng图片在premiere和ae中不一致
- socket网络编程套接字TCP/UDP两种方式详解
- 如何在iOS应用中使用自定义字体
- [AH2017/HNOI2017]影魔
- 11_创建ROS msg和srv文件