注:目前大部分省份已上线国家医保,读取社会保障卡可以直接问医院要当地医保局下发的动态库进行读取。每个省份读取方式均有差异。
大部分地区支持读卡器免Psam卡交易。
文章中有测试工具与最新德卡提供的对应开发包。
补充遗漏的方法:Common.getNation、 Hex2ByteArr
--------------------------------------------------------------------------------------------------------------------------------
参考地址:https://so.csdn.net/so/search?q=%E7%A4%BE%E4%BF%9D%E5%8D%A1&t=blog&u=weixin_30485799
引用的SDK方法
[DllImport("dcrf32.dll")]
public static extern short dc_beep(int icdev, ushort _Msec);//设备蜂鸣
[DllImport("dcrf32.dll")]
public static extern short dc_setcpu(int icdev, [In]byte _Byte); //设置当前接触式卡座
[DllImport("dcrf32.dll")]
public static extern short dc_cpureset(int icdev, ref byte rlen, [Out]byte[] databuffer);//接触式CPU卡复位
[DllImport("dcrf32.dll")]
public static extern short hex_a([In] byte[] hex, [Out] byte[] a, short length);//普通数据转换16进制字符串(短转长)
[DllImport("dcrf32.dll")]
public static extern short dc_cpuapduInt(int icdev, uint slen, [In]byte[] sendbuffer, ref uint rlen, [Out]byte[] databuffer);//指令交互
社保卡信息类
public class MedicareCard
{
/// <summary>
/// 发卡地区行政区划代码(卡识别码前6位)
/// </summary>
public string IssuingAreaCode { get; set; }
/// <summary>
/// 社会保障号码(身份证号码)
/// </summary>
public string SocialNo{ get; set; }
/// <summary>
/// 卡号
/// </summary>
public string HealthCareCardNo{ get; set; }
/// <summary>
/// 卡识别码
/// </summary>
public string IdentificationCode{ get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name{ get; set; }
/// <summary>
/// 出生地
/// </summary>
public string Address{ get; set; }
/// <summary>
/// 性别
/// </summary>
public string Sex{ get; set; }
/// <summary>
/// 民族
/// </summary>
public string Nation{ get; set; }
/// <summary>
/// 出生日期
/// </summary>
public string Birthdate{ get; set; }
/// <summary>
/// 社保卡余额
/// </summary>
public string Balance{ get; set; }
/// <summary>
/// 卡复位信息(仅取历史字节)
/// </summary>
public string CardResetInformation{ get; set; }
/// <summary>
/// 规范版本
/// </summary>
public string CanonicalVersion{ get; set; }
/// <summary>
/// 发卡日期
/// </summary>
public string StartDate{ get; set; }
/// <summary>
/// 卡有效期
/// </summary>
public string EndDate{ get; set; }
/// <summary>
/// 终端机编号
/// </summary>
public string TerminalNO{ get; set; }
/// <summary>
/// 终端设备号
/// </summary>
public string TerminalEquipmentNo{ get; set; }
}
调用代码
public MedicareCard IC_ReadMedicare()
{
MedicareCard CraeCard = new MedicareCard();
string str;
int st;
dc_beep(Handle, 10);
//射频复位
dc_setcpu(Handle, (byte)ContactClamp.NO1); //设置接触式卡座
byte rcardlen = 0;
uint rlen = 0;
byte[] databuffer = new byte[100];
byte[] databufferhex = new byte[100];
dc_cpureset(Handle, ref rcardlen, databuffer);//接触式CPU卡复位
hex_a(databuffer, databufferhex, (short)rlen);
/*
选择应用环境 00 A4 04 00 0F 73 78 31 2E 73 68 2E C9 E7 BB E1 B1 A3 D5 CF 00
选择EF05文件 00 A4 02 00 02 EF 05 00 选择EF06文件 00A4020002EF0600
读卡号 00 B2 07 00 0B
读取社会保障卡号码 00 B2 08 00 14
读姓名 00 B2 09 00 20
读性别 00 B2 0A 00 03
读民族 00 B2 0B 00 03
读出生日期 00 B2 0D 00 06
*/
byte[] sendbuffer = new byte[22];
sendbuffer[0] = 0x00;
sendbuffer[1] = 0xA4;
sendbuffer[2] = 0x04;
sendbuffer[3] = 0x00;
sendbuffer[4] = 0x0F;
sendbuffer[5] = 0x73;
sendbuffer[6] = 0x78;
sendbuffer[7] = 0x31;
sendbuffer[8] = 0x2E;
sendbuffer[9] = 0x073;
sendbuffer[10] = 0x68;
sendbuffer[11] = 0x2E;
sendbuffer[12] = 0xC9;
sendbuffer[13] = 0xE7;
sendbuffer[14] = 0xBB;
sendbuffer[15] = 0xE1;
sendbuffer[16] = 0xB1;
sendbuffer[17] = 0xA3;
sendbuffer[18] = 0xD5;
sendbuffer[19] = 0xCF;
sendbuffer[20] = 0x00;
st = dc_cpuapduInt(Handle, 21, sendbuffer, ref rlen, databuffer);// 选择应用环境 00 A4 04 00 0F 73 78 31 2E 73 68 2E C9 E7 BB E1 B1 A3 D5 CF 00
byte[] sendbuffer1 = new byte[9];
sendbuffer1[0] = 0x00;
sendbuffer1[1] = 0xA4;
sendbuffer1[2] = 0x02;
sendbuffer1[3] = 0x00;
sendbuffer1[4] = 0x02;
sendbuffer1[5] = 0xEF;
sendbuffer1[6] = 0x05;
sendbuffer1[7] = 0x00;
st = dc_cpuapduInt(Handle, 8, sendbuffer1, ref rlen, databuffer);// 选择EF05文件 00 A4 02 00 02 EF 05 00
byte[] sendbuffer2 = new byte[6];
sendbuffer2[0] = 0x00;
sendbuffer2[1] = 0xB2;
sendbuffer2[2] = 0x07;
sendbuffer2[3] = 0x00;
sendbuffer2[4] = 0x0B;
st = dc_cpuapduInt(Handle, 5, sendbuffer2, ref rlen, databuffer);//读社保卡号
if (st != 0)
{
return null;
}
else
{
hex_a(databuffer, databufferhex, (short)rlen);
str = Encoding.Default.GetString(databufferhex);
string DealDate = str.Substring(4, 18);
string tempbuffer = Encoding.Default.GetString(Common.Hex2ByteArr(DealDate));
CraeCard.HealthCareCardNo = tempbuffer;
}
byte[] sendbuffer1_2 = new byte[6];
sendbuffer1_2[0] = 0x00;
sendbuffer1_2[1] = 0xB2;
sendbuffer1_2[2] = 0x05;
sendbuffer1_2[3] = 0x00;
sendbuffer1_2[4] = 0x06;
st = dc_cpuapduInt(Handle, 5, sendbuffer1_2, ref rlen, databuffer); //发卡日期
if (st != 0)
{
return null;
}
else
{
hex_a(databuffer, databufferhex, (short)rlen);
str = Encoding.Default.GetString(databufferhex);
string DealDate = str.Substring(4, 8);
CraeCard.StartDate = DealDate;
}
byte[] sendbuffer1_3 = new byte[6];
sendbuffer1_3[0] = 0x00;
sendbuffer1_3[1] = 0xB2;
sendbuffer1_3[2] = 0x06;
sendbuffer1_3[3] = 0x00;
sendbuffer1_3[4] = 0x06;
st = dc_cpuapduInt(Handle, 5, sendbuffer1_3, ref rlen, databuffer); //卡有效期
if (st != 0)
{
return null;
}
else
{
hex_a(databuffer, databufferhex, (short)rlen);
str = Encoding.Default.GetString(databufferhex);
string DealDate = str.Substring(4, 8);
CraeCard.EndDate = DealDate;
}
byte[] sendbuffer1_4 = new byte[6];
sendbuffer1_4[0] = 0x00;
sendbuffer1_4[1] = 0xB2;
sendbuffer1_4[2] = 0x01;
sendbuffer1_4[3] = 0x00;
sendbuffer1_4[4] = 0x12;
st = dc_cpuapduInt(Handle, 5, sendbuffer1_4, ref rlen, databuffer); //卡识别码
if (st != 0)
{
return null;
}
else
{
hex_a(databuffer, databufferhex, (short)rlen);
str = Encoding.Default.GetString(databufferhex);
string DealDate = str.Substring(4, 32);
CraeCard.IdentificationCode = DealDate;
CraeCard.IssuingAreaCode = DealDate.Substring(0, 6);
}
//
byte[] sendbuffer2_1 = new byte[9];
sendbuffer2_1[0] = 0x00;
sendbuffer2_1[1] = 0xA4;
sendbuffer2_1[2] = 0x02;
sendbuffer2_1[3] = 0x00;
sendbuffer2_1[4] = 0x02;
sendbuffer2_1[5] = 0xEF;
sendbuffer2_1[6] = 0x06;
sendbuffer2_1[7] = 0x00;
st = dc_cpuapduInt(Handle, 8, sendbuffer2_1, ref rlen, databuffer);// 选择EF06文件 00A4020002EF0600
byte[] sendbuffer3 = new byte[6];
sendbuffer3[0] = 0x00;
sendbuffer3[1] = 0xB2;
sendbuffer3[2] = 0x08;
sendbuffer3[3] = 0x00;
sendbuffer3[4] = 0x14;
st = dc_cpuapduInt(Handle, 5, sendbuffer3, ref rlen, databuffer);//读社会保障卡号码00 B2 08 00 14
if (st != 0)
{
return null;
}
else
{
hex_a(databuffer, databufferhex, (short)rlen);
str = Encoding.Default.GetString(databufferhex);
string DealDate = str.Substring(4, 36);
string tempbuffer = Encoding.Default.GetString(Common.Hex2ByteArr(DealDate));
CraeCard.SocialNo = tempbuffer;
}
byte[] sendbuffer4 = new byte[6];
sendbuffer4[0] = 0x00;
sendbuffer4[1] = 0xB2;
sendbuffer4[2] = 0x09;
sendbuffer4[3] = 0x00;
sendbuffer4[4] = 0x20;
st = dc_cpuapduInt(Handle, 5, sendbuffer4, ref rlen, databuffer);//姓名00 B2 09 00 20 //091ED3DAD1F3D1F30000000000000000000000000000000000000000000000009000
if (st != 0)
{
return null;
}
else
{
hex_a(databuffer, databufferhex, (short)rlen);
str = Encoding.Default.GetString(databufferhex);
string DealDate = str.Substring(4, 12);
string tempbuffer = Encoding.Default.GetString(Common.Hex2ByteArr(DealDate));
CraeCard.Name = tempbuffer.TrimEnd('\0');//去除\0 避免序列化出错
}
//
byte[] sendbuffer5 = new byte[6];
sendbuffer5[0] = 0x00;
sendbuffer5[1] = 0xB2;
sendbuffer5[2] = 0x0A;
sendbuffer5[3] = 0x00;
sendbuffer5[4] = 0x03;
st = dc_cpuapduInt(Handle, 5, sendbuffer5, ref rlen, databuffer);//性别00 B2 0A 00 03
if (st != 0)
{
return null;
}
else
{
hex_a(databuffer, databufferhex, (short)rlen);
str = Encoding.Default.GetString(databufferhex);//0A01329000
string DealDate = str.Substring(4, 2);
string tempbuffer = Encoding.Default.GetString(Common.Hex2ByteArr(DealDate)) == "1" ? "男" : "女";
CraeCard.Sex = tempbuffer;
}
byte[] sendbuffer6 = new byte[6];
sendbuffer6[0] = 0x00;
sendbuffer6[1] = 0xB2;
sendbuffer6[2] = 0x0B;
sendbuffer6[3] = 0x00;
sendbuffer6[4] = 0x03;
st = dc_cpuapduInt(Handle, 5, sendbuffer6, ref rlen, databuffer);//民族00 B2 0B 00 03
if (st != 0)
{
return null;
}
else
{
hex_a(databuffer, databufferhex, (short)rlen);
str = Encoding.Default.GetString(databufferhex);
string DealDate = Common.getNational(str.Substring(4, 2));
CraeCard.Nation = DealDate;
}
byte[] sendbuffer7 = new byte[6];
sendbuffer7[0] = 0x00;
sendbuffer7[1] = 0xB2;
sendbuffer7[2] = 0x0D;
sendbuffer7[3] = 0x00;
sendbuffer7[4] = 0x06;
st = dc_cpuapduInt(Handle, 5, sendbuffer7, ref rlen, databuffer);//出生日期00 B2 0D 00 06
if (st != 0)
{
return null;
}
else
{
hex_a(databuffer, databufferhex, (short)rlen);
str = Encoding.Default.GetString(databufferhex);
string DealDate = str.Substring(4, 8);
CraeCard.Birthdate = DealDate;
}
return CraeCard;
}
公用方法
public static class Common
{
public static string Description(this Enum value)
{
FieldInfo field = value.GetType().GetField(value.ToString());
return !(Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attribute) ? value.ToString() : attribute.Description;
}
/// <summary>
/// 十六进制字符串转16进制字节数组
/// </summary>
/// <param name="hexString"></param>
/// <returns></returns>
public static byte[] Hex2ByteArr(string newString)
{
byte[] arr = new byte[0];
try
{
if (newString == null)
{
byte[] NullArr = new byte[6];
return NullArr;
}
int len = newString.Length / 2;
arr = new byte[len];
for (int i = 0; i < len; i++)
{
arr[i] = Convert.ToByte(newString.Substring(i * 2, 2), 16);
}
}
catch { }
return arr;
}
/// <summary>
/// BYTE 数组转 十六进制字符串
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static string ToHexString(byte[] bytes)
{
string hexString = string.Empty;
if (bytes != null)
{
StringBuilder strB = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
strB.Append(bytes[i].ToString("X2"));
}
hexString = strB.ToString();
}
return hexString;
}
public static string StringHandle(byte[] value, bool isChinese = false)
{
string text;
if (isChinese)
{
text = Encoding.GetEncoding("gb2312").GetString(value);
}
else text = Encoding.Default.GetString(value);
Log.Debug("[Byte[] To String]", text);
return text.Trim();
}
/// <summary>
/// String转Byte[]
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static byte[] StringToByte(string str)
{
return str == null ? null : Encoding.Default.GetBytes(str);
}
/// <summary>
/// byte[]转string
/// </summary>
/// <param name="bt"></param>
/// <returns></returns>
public static string ByteToString(byte[] bt)
{
return bt == null ? null : Encoding.Default.GetString(bt);
}
/// <summary>
/// 获取民族
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
public static string CodeToNational(string code)
{
string result;
switch (code)
{
case "01":
result = "汉族";
break;
case "02":
result = "蒙古族";
break;
case "03":
result = "回族";
break;
case "04":
result = "藏族";
break;
case "05":
result = "维吾尔族";
break;
case "06":
result = "苗族";
break;
case "07":
result = "彝族";
break;
case "08":
result = "壮族";
break;
case "09":
result = "布依族";
break;
case "10":
result = "朝鲜族";
break;
case "11":
result = "满族";
break;
case "12":
result = "侗族";
break;
case "13":
result = "瑶族";
break;
case "14":
result = "白族";
break;
case "15":
result = "土家族";
break;
case "16":
result = "哈尼族";
break;
case "17":
result = "哈萨克族";
break;
case "18":
result = "傣族";
break;
case "19":
result = "黎族";
break;
case "20":
result = "僳僳族";
break;
case "21":
result = "佤族";
break;
case "22":
result = "畲族";
break;
case "23":
result = "高山族";
break;
case "24":
result = "拉祜族";
break;
case "25":
result = "水族";
break;
case "26":
result = "东乡族";
break;
case "27":
result = "纳西族";
break;
case "28":
result = "景颇族";
break;
case "29":
result = "柯尔克孜族";
break;
case "30":
result = "土族";
break;
case "31":
result = "达斡尔族";
break;
case "32":
result = "仫佬族";
break;
case "33":
result = "羌族";
break;
case "34":
result = "布朗族";
break;
case "35":
result = "撒拉族";
break;
case "36":
result = "毛难族";
break;
case "37":
result = "仡佬族";
break;
case "38":
result = "锡伯族";
break;
case "39":
result = "阿昌族";
break;
case "40":
result = "普米族";
break;
case "41":
result = "塔吉克族";
break;
case "42":
result = "怒族";
break;
case "43":
result = "乌孜别克族";
break;
case "44":
result = "俄罗斯族";
break;
case "45":
result = "鄂温克族";
break;
case "46":
result = "崩龙族";
break;
case "47":
result = "保安族";
break;
case "48":
result = "裕固族";
break;
case "49":
result = "京族";
break;
case "50":
result = "塔塔尔族";
break;
case "51":
result = "独龙族";
break;
case "52":
result = "鄂伦春族";
break;
case "53":
result = "赫哲族";
break;
case "54":
result = "门巴族";
break;
case "55":
result = "珞巴族";
break;
case "56":
result = "基诺族";
break;
default:
result = "其他";
break;
}
return result;
}
}