@li0ard/tsemrtd
Version:
simple library for eMRTD. supports browsers, node, bun and more!
134 lines (133 loc) • 5.34 kB
JavaScript
import { TLV } from "@li0ard/tinytlv";
import { Enums, Interfaces, Schemas, Utils } from "./index";
import { AsnConvert } from "@peculiar/asn1-schema";
/**
* Class for working with DG4 (Iris)
* @hideconstructor
* @experimental
*/
export class DG4 {
/**
* Extract int from Uint8Array
* @hidden
* @param data Uint8Array
* @param start Offset
* @param end Offset+length
*/
extractContent(data, start, end) {
if (end - start === 1) {
return data[start];
}
else if (end - start < 4) {
return (data[start] << 8) | data[start + 1];
}
else if (end - start == 4) {
return (data[start] << 24) | (data[start + 1] << 16) | (data[start + 2] << 8) | data[start + 3];
}
return parseInt(Utils.bytesToHex(data.slice(start, end)), 16);
}
/**
* Read Biometric data block
* @param tlv
*/
readBDB(tlv) {
if (parseInt(tlv.tag, 16) != 0x7f60)
throw new Error(`Invalid object tag "0x${tlv.tag}", expected 0x7f60`);
let sbh = AsnConvert.parse(tlv.childs[0].toBytes(), Schemas.SBH);
let firstBlock = tlv.childs[1];
if (parseInt(firstBlock.tag, 16) != 0x5f2e && parseInt(firstBlock.tag, 16) != 0x7f2e)
throw new Error(`Invalid object tag "0x${tlv.tag}", expected 0x5f2e or 0x7f2e`);
let data = firstBlock.byteValue;
if (this.extractContent(data, 0, 4) != 0x49495200)
throw new Error("Biometric data block is invalid");
let offset = 4;
if (this.extractContent(data, offset, offset + 4) != 0x30313000)
throw new Error("Version of Biometric data is not valid");
offset += 4;
let lengthOfRecord = this.extractContent(data, offset, offset + 4);
offset += 4;
//let dataLength = lengthOfRecord - 45;
let captureDeviceId = this.extractContent(data, offset, offset + 2);
offset += 2;
let count = this.extractContent(data, offset, offset + 1);
offset += 1;
if (count > 1)
console.warn("[DG4] The record contains more than 1 image.");
let recordHeaderLength = this.extractContent(data, offset, offset + 2);
offset += 2;
if (recordHeaderLength != 45)
throw new Error(`Expected header length 45, found ${recordHeaderLength}`);
let imagePropertiesBits = this.extractContent(data, offset, offset + 2);
offset += 2;
let irisDiameter = this.extractContent(data, offset, offset + 2);
offset += 2;
let imageType = this.extractContent(data, offset, offset + 2);
offset += 2;
let imageWidth = this.extractContent(data, offset, offset + 2);
offset += 2;
let imageHeight = this.extractContent(data, offset, offset + 2);
offset += 2;
let depth = this.extractContent(data, offset, offset + 1);
offset += 1;
let imageTransformation = this.extractContent(data, offset, offset + 1);
offset += 1;
let deviceUniqueId = this.extractContent(data, offset, offset + 16);
offset += 16;
let biometricSubtype = this.extractContent(data, offset, offset + 1);
offset += 1;
let biometricSubtypeCount = this.extractContent(data, offset, offset + 2);
offset += 2;
if (biometricSubtypeCount > 1)
console.warn("[DG4] The record contains more than 1 image.");
let imageNumber = this.extractContent(data, offset, offset + 2);
offset += 2;
let quality = this.extractContent(data, offset, offset + 1);
offset += 1;
let rotationAngle = this.extractContent(data, offset, offset + 2);
offset += 2;
let rotationAngleUncertainty = this.extractContent(data, offset, offset + 2);
offset += 2;
let imageEnd = this.extractContent(data, offset, offset + 4) & 4294967295;
offset += 4;
let imageData = data.subarray(offset, offset + imageEnd);
return {
sbh,
lengthOfRecord,
captureDeviceId,
imagePropertiesBits,
irisDiameter,
imageType,
imageWidth,
imageHeight,
depth,
imageTransformation,
deviceUniqueId,
biometricSubtype,
quality,
rotationAngle,
rotationAngleUncertainty,
imageData
};
}
/**
* Get image of eye iris
* @param data Data of EF.DG4 file
*/
static load(data) {
let tlv = TLV.parse(data);
if (parseInt(tlv.tag, 16) != Enums.TAGS.DG4)
throw new Error(`Invalid DG4 tag "0x${tlv.tag}", expected 0x${Enums.TAGS.DG4.toString(16)}`);
let bigt = tlv.childs[0];
if (parseInt(bigt.tag, 16) != 0x7f61)
throw new Error(`Invalid object tag "0x${bigt.tag}", expected 0x7f61`);
let bict = bigt.childs[0];
if (parseInt(bict.tag, 16) != 0x02)
throw new Error(`Invalid object tag "0x${bict.tag}", expected 0x02`);
let bitCount = parseInt(bigt.childs[0].value, 16);
let results = [];
for (let i = 0; i < bitCount; i++) {
results.push(new DG4().readBDB(bigt.childs[i + 1]));
}
return results;
}
}