如何从Aadhaar卡的安全QR码中验证手机号码和电子邮件ID

huangapple go评论77阅读模式
英文:

How to Verify Mobile no and email id from Secure QR code of Aadhaar card

问题

以下是代码部分的翻译:

public ScanResult(String input) {
    // ...(略去部分代码)

    if (rawString.matches("[0-9]*")) {
        type = QR_CODE_TYPE_SECURE;
        byte[] msgInBytes = null;
        try {
            msgInBytes = decompressByteArray(new BigInteger(rawString).toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (msgInBytes != null) {
            int[] delimiters = locateDelimiters(msgInBytes);
            String referenceId = getValueInRange(msgInBytes, delimiters[0] + 1, delimiters[1]);
            uid = referenceId.substring(0, 4);
            // ...(略去部分代码)
        } else {
            // ...(略去部分代码)
        }
    } else {
        type = QR_CODE_TYPE_UNKNOWN;
        statusCode = STATUS_PARSE_ERROR;
        // ...(略去部分代码)
    }

    dobGuess = getDobGuess(dob, yob);
    statusText = getStatusText(statusCode);
}

private static int[] locateDelimiters(byte[] msgInBytes) {
    // ...(略去部分代码)
}

private static String getValueInRange(byte[] msgInBytes, int start, int end) {
    return new String(Arrays.copyOfRange(msgInBytes, start, end), Charset.forName("ISO-8859-1"));
}

private static int getNextDelimiterIndex(byte[] msgInBytes, int index) {
    // ...(略去部分代码)
}

private static byte[] decompressByteArray(byte[] bytes) throws IOException {
    // ...(略去部分代码)
}

private String formatDate(String rawDateString, String[] possibleFormats) {
    // ...(略去部分代码)
}

@NonNull
protected String formatGender(String gender) throws ParseException {
    // ...(略去部分代码)
}

@NonNull
private String getStatusText(int statusCode) {
    switch (statusCode) {
        case ScanResult.STATUS_SUCCESS:
            return "✓";
        default:
            return "✗";
    }
}

@NonNull
private String getDobGuess(String dob, String yob) {
    if (dob.equals("")) {
        Integer yearInt;
        try {
            yearInt = Integer.parseInt(yob);
        } catch (NumberFormatException e) {
            return "";
        }
        // June 1 of the year
        return Integer.toString(yearInt) + "-06-01";
    } else {
        return dob;
    }
}

以上是你提供的代码部分的翻译。如果你还有其他需要翻译的内容,请继续提供。

英文:

Official Document for How to Read QR code data from Secure QR code of UIDAI Aadhaar card: https://uidai.gov.in/images/resource/User_manulal_QR_Code_15032019.pdf

Have used zxing scanner to scan Secure QR code,
And was able to get details of aadhar card with the help of follow project in Github:
https://github.com/dimagi/AadharUID

Some how I figured out how to extract photo and bit_indicator_value from converted byte array with the help of instructions on document

But I am unable to get hashed exact hashed value of email and mobile from Secure QR code of Aadhar card byte array to verify

I am bit confused from this line of above mentioned document in page no 6:

  • Post getting signature value, check the value of
    Email_mobile_present_bit_indicator_value:
  1. if its 3 then first read mobile from index (Byte array length – 1-256) and then email from index (Byte array length – 1- 256- 32) in
    reverse order. Each value will be of fix size of 32 byte.
  2. If Email_mobile_present_bit_indicator_value is 1 then only mobile
    is present.
  3. If Email_mobile_present_bit_indicator_value is 2 then only email is
    present.
  4. If Email_mobile_present_bit_indicator_value is 0 then no mobile or
    email present.
  • Email and Mobile value will available in byte. Convert into Hexadecimal
    String.
    .

I have also prepared last step in document page no 6 but the users mobile/email hash value and documents mobile/email byte arrays hash value never matches

Code snippet:

    public ScanResult(String input) {
rawString = input;
// copied from http://www.java-samples.com/showtutorial.php?tutorialid=152
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
Document dom;
try {
//Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
// Replace </?xml... with <?xml...
if (input.startsWith("</?")) {
input = input.replaceFirst("</\\?", "<?");
}
// Replace <?xml...?"> with <?xml..."?>
input = input.replaceFirst("^<\\?xml ([^>]+)\\?\">", "<?xml $1\"?>");
//parse using builder to get DOM representation of the XML file
dom = db.parse(new ByteArrayInputStream(input.getBytes("UTF-8")));
} catch (ParserConfigurationException | SAXException | IOException e) {
dom = null;
}
if (rawString.matches("[0-9]*")) {
type = QR_CODE_TYPE_SECURE;
byte[] msgInBytes = null;
try {
msgInBytes = decompressByteArray(new BigInteger(rawString).toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
if (msgInBytes != null) {
int[] delimiters = locateDelimiters(msgInBytes);
String referenceId = getValueInRange(msgInBytes, delimiters[0] + 1, delimiters[1]);
uid = referenceId.substring(0, 4);
name = getValueInRange(msgInBytes, delimiters[1] + 1, delimiters[2]);
dob = formatDate(getValueInRange(msgInBytes, delimiters[2] + 1, delimiters[3]),
new String[] {"dd-MM-yyyy", "dd/MM/yyyy"});
yob = dob.substring(0, 4);
gender = getValueInRange(msgInBytes, delimiters[3] + 1, delimiters[4]);
co = getValueInRange(msgInBytes, delimiters[4] + 1, delimiters[5]);
dist = getValueInRange(msgInBytes, delimiters[5] + 1, delimiters[6]);
lm = getValueInRange(msgInBytes, delimiters[6] + 1, delimiters[7]);
house = getValueInRange(msgInBytes, delimiters[7] + 1, delimiters[8]);
loc = getValueInRange(msgInBytes, delimiters[8] + 1, delimiters[9]);
pc = getValueInRange(msgInBytes, delimiters[9] + 1, delimiters[10]);
po = getValueInRange(msgInBytes, delimiters[10] + 1, delimiters[11]);
state = getValueInRange(msgInBytes, delimiters[11] + 1, delimiters[12]);
street = getValueInRange(msgInBytes, delimiters[12] + 1, delimiters[13]);
subdist = getValueInRange(msgInBytes, delimiters[13] + 1, delimiters[14]);
vtc = getValueInRange(msgInBytes, delimiters[14] + 1, delimiters[15]);
statusCode = STATUS_SUCCESS;
} else {
statusCode = STATUS_PARSE_ERROR;
uid = "";
name = "";
gender = "";
yob = "";
co = "";
house = "";
street = "";
lm = "";
loc = "";
vtc = "";
po = "";
dist = "";
subdist = "";
state = "";
pc = "";
dob = "";
}
} else {
type = QR_CODE_TYPE_UNKNOWN;
statusCode = STATUS_PARSE_ERROR;
uid = "";
name = "";
gender = "";
yob = "";
co = "";
house = "";
street = "";
lm = "";
loc = "";
vtc = "";
po = "";
dist = "";
subdist = "";
state = "";
pc = "";
dob = "";
}
dobGuess = getDobGuess(dob, yob);
statusText = getStatusText(statusCode);
}
private static int[] locateDelimiters(byte[] msgInBytes) {
int[] delimiters = new int[NUMBER_OF_PARAMS_IN_SECURE_QR_CODE + 1];
int index = 0;
int delimiterIndex;
for (int i = 0; i <= NUMBER_OF_PARAMS_IN_SECURE_QR_CODE; i++) {
delimiterIndex = getNextDelimiterIndex(msgInBytes, index);
delimiters[i] = delimiterIndex;
index = delimiterIndex + 1;
}
return delimiters;
}
private static String getValueInRange(byte[] msgInBytes, int start, int end) {
return new String(Arrays.copyOfRange(msgInBytes, start, end), Charset.forName("ISO-8859-1"));
}
private static int getNextDelimiterIndex(byte[] msgInBytes, int index) {
int i = index;
for (; i < msgInBytes.length; i++) {
if (msgInBytes[i] == -1) {
break;
}
}
return i;
}
private static byte[] decompressByteArray(byte[] bytes) throws IOException {
java.io.ByteArrayInputStream bytein = new ByteArrayInputStream(bytes);
java.util.zip.GZIPInputStream gzin = new GZIPInputStream(bytein);
java.io.ByteArrayOutputStream byteout = new ByteArrayOutputStream();
int res = 0;
byte buf[] = new byte[1024];
while (res >= 0) {
res = gzin.read(buf, 0, buf.length);
if (res > 0) {
byteout.write(buf, 0, res);
}
}
return byteout.toByteArray();
}
private String formatDate(String rawDateString, String[] possibleFormats) {
if (rawDateString.equals("")) {
return "";
}
SimpleDateFormat toFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
ParseException parseException = null;
for (String fromFormatPattern : possibleFormats) {
try {
SimpleDateFormat fromFormat = new SimpleDateFormat(fromFormatPattern);
date = fromFormat.parse(rawDateString);
break;
} catch (ParseException e) {
parseException = e;
}
}
if (date != null) {
return toFormat.format(date);
} else if (parseException != null) {
System.err.println("Expected dob to be in dd/mm/yyyy or yyyy-mm-dd format, got " + rawDateString);
return rawDateString;
} else {
throw new AssertionError("This code is unreachable");
}
}
@NonNull
protected String formatGender(String gender) throws ParseException {
String lowercaseGender = gender.toLowerCase();
if (lowercaseGender.equals("male") || lowercaseGender.equals("m")) {
return "M";
} else if (lowercaseGender.equals("female") || lowercaseGender.equals("f")) {
return "F";
} else if (lowercaseGender.equals("other") || lowercaseGender.equals("o")) {
return "O";
} else {
throw new ParseException("404 gender not found", 0);
}
}
@NonNull
private String getStatusText(int statusCode) {
switch (statusCode) {
case ScanResult.STATUS_SUCCESS:
return "✓";
default:
return "✗";
}
}
@NonNull
private String getDobGuess(String dob, String yob) {
if (dob.equals("")) {
Integer yearInt;
try {
yearInt = Integer.parseInt(yob);
} catch (NumberFormatException e) {
return "";
}
// June 1 of the year
return Integer.toString(yearInt) + "-06-01";
} else {
return dob;
}
}

Github Code Link

答案1

得分: 2

刚刚得到解决方案,从字节数组中获取了确切的手机号码和电子邮件哈希值。

首先从字节数组中移除最后的256字节,然后:

如果只有手机号码,则从字节数组中取最后的32字节作为手机号码,
即(数组长度 - 32 到 数组长度)

如果只有电子邮件,则从字节数组中取最后的32字节作为电子邮件,
即(数组长度 - 32 到 数组长度)

如果既有电子邮件又有手机号码,则从字节数组中取最后的32字节作为手机号码,再取倒数第二个32字节作为电子邮件,
即(手机号码 = 数组长度 - 32 到 数组长度,且
电子邮件 = 数组长度 - 64 到 数组长度 - 32)

英文:

Just now got the solution, fetched exact mobile and email hash value from byte array

first remove last 256 bytes from byte array then,

if only mobile present then take last 32 bytes from byte array for mobile
i.e. (array.length - 32 to array.length)

else if only email present then take last 32 bytes from byte array for email i.e. (array.length - 32 to array.length)

else if both email and mobile present then take last 32 bytes from byte array for mobile, take next last 32 bytes for email
i.e. (mobile = array.length - 32 to array.length and
email = array.length - 64 to array.length - 32)

答案2

得分: 1

从字节数组中,您需要从索引byte_array_length - 256 - 32byte_array_length - 256 读取值,以获得移动哈希的字节表示(您可以轻松将字节转换为十六进制字符串)。类似地,对于电子邮件,您需要从索引byte_array_length - 256 - 32 - 32byte_array_length - 256 - 32 进行读取。

我已经实现了一个用于解码的库,但该实现是使用Python完成的。

虽然这个问题有点旧,但未来的读者可能会发现这些资源很有用。

PyPI: aadhaar-py

Github: https://github.com/vishaltanwar96/aadhaar-py

英文:

From the byte array you need to read values from index byte_array_length - 256 - 32 to byte_array_length - 256 to get the mobile hash in bytes(you can easily convert the bytes to hexadecimal string) and similarly for email you need to read from index byte_array_length - 256 - 32 - 32 to byte_array_length - 256 - 32.

I have implemented a library for decoding the same but the implementation is in Python.

The question is a bit old but future readers might find these resources useful.

PyPI: aadhaar-py

Github: https://github.com/vishaltanwar96/aadhaar-py

huangapple
  • 本文由 发表于 2020年10月14日 02:41:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/64341259.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定