Skip to content

Instantly share code, notes, and snippets.

@Porush
Created September 30, 2022 05:43
Show Gist options
  • Select an option

  • Save Porush/b887c48b569cb988ebf5a03da0dfdbd5 to your computer and use it in GitHub Desktop.

Select an option

Save Porush/b887c48b569cb988ebf5a03da0dfdbd5 to your computer and use it in GitHub Desktop.
public static function uidai_validate($uidai, $passcode)
{
$result = array(
'success' => false,
'error' => '',
'uidai' => '',
'img' => '',
'first_name' => '',
'last_name' => '',
'birth_date' => '',
'gender' => '',
'state' => '',
'city' => '',
'address' => ''
);
$xml_file = null;
$zip_file = new ZipArchive();
$zip_file_path = Storage::disk('data')->path('aadhaar_zip/' . $uidai . '.zip');
$zip_file_status = $zip_file->open($zip_file_path);
if ($zip_file_status === true) {
$zip_file->setPassword($passcode);
if ($zip_file->extractTo(Storage::disk('data')->path('aadhaar_xml'))) {
if (!str_ends_with($zip_file->getNameIndex(0), '.xml')) {
$result['error'] = 3;
return $result;
}
$xml_file = Storage::disk('data')->get('aadhaar_xml/' . $zip_file->getNameIndex(0));
} else {
$result['error'] = 2; // Invalid passcode
}
$zip_file->close();
unlink($zip_file_path);
} else {
$result['error'] = 1; // Unable to open file
}
if ($xml_file) {
$key_file = Storage::get("files/uidai_auth_sign_prod_2023.cer");
$key_file = openssl_x509_read($key_file);
$xmlDoc = new DOMDocument();
$xmlDoc->loadXML($xml_file);
$xml_data = simplexml_load_string($xml_file, null, LIBXML_NOBLANKS) or dd("Failed to load");
$xml_array = self::xml2array($xml_data);
$reference_id = $xml_array['@attributes']['referenceId'];
$aadhar_id = substr($reference_id, 0, 4);
$time_stamp = substr($reference_id, 4);
$photo = $xml_array['UidData']['Pht'];
$dob = $xml_array['UidData']['Poi']['@attributes']['dob'];
$email_hashed = $xml_array['UidData']['Poi']['@attributes']['e'];
$gender = $xml_array['UidData']['Poi']['@attributes']['gender'];
$mobile_hashed = $xml_array['UidData']['Poi']['@attributes']['m'];
$name = $xml_array['UidData']['Poi']['@attributes']['name'];
$country = $xml_array['UidData']['Poa']['@attributes']['country'];
$district = $xml_array['UidData']['Poa']['@attributes']['dist'];
$address = $xml_array['UidData']['Poa']['@attributes']['house'];
$landmark = $xml_array['UidData']['Poa']['@attributes']['landmark'];
$loc = $xml_array['UidData']['Poa']['@attributes']['loc'];
$pincode = $xml_array['UidData']['Poa']['@attributes']['pc'];
$postoffice = $xml_array['UidData']['Poa']['@attributes']['po'];
$state = $xml_array['UidData']['Poa']['@attributes']['state'];
$street = $xml_array['UidData']['Poa']['@attributes']['street'];
$subdistrict = $xml_array['UidData']['Poa']['@attributes']['subdist'];
$vtc = $xml_array['UidData']['Poa']['@attributes']['vtc'];
$from = new DateTime(date('Y-m-d', strtotime($dob)));
$to = new DateTime('today');
$age = $from->diff($to)->y;
$hash_count = substr($aadhar_id, -1); //8
if ($hash_count == 0) {
$hash_count = 1;
}
// Getting SignatureValue from XML
$signature = $xml_array['Signature']['SignatureValue'];
$signed_info = $xmlDoc->getElementsByTagName('SignedInfo')[0];
$signed_info = $signed_info->C14N();
$signed_info = hash('sha1', $signed_info);
// Getting DigestValue from XML
$digest = $xml_array['Signature']['SignedInfo']['Reference']['DigestValue'];
$digest = bin2hex(base64_decode($digest));
// Removing Signature Part from XML
$xml_child = $xml_data->xpath("/OfflinePaperlessKyc");
$xml_child = get_object_vars($xml_child[0]);
$xml_child = $xml_child['Signature'];
unset($xml_child[0]);
$xml_without_signature = strval($xml_data->asXML());
$xmlDoc->loadXML($xml_without_signature);;
$data = $xmlDoc->C14N();
$digest_test = hash('sha256', $data);
//XML Data is Verified by DigestValue
if ($digest == $digest_test) {
$pub_key = openssl_pkey_get_public($key_file);
$details = openssl_pkey_get_details($pub_key);
$array = openssl_pkey_get_details($pub_key);
$hex = array_map("bin2hex", $array["rsa"]);
//For decryption we would use:
$decrypted = '';
//decode must be done before spliting for getting the binary String
$test_data = str_split(base64_decode($signature), 256);
foreach ($test_data as $chunk) {
$partial = '';
//be sure to match padding
$decryptionOK = openssl_public_decrypt($chunk, $partial, $details['key'], OPENSSL_PKCS1_PADDING);
if ($decryptionOK === false) {
//return false;
dd(openssl_error_string());
continue;
} //here also processed errors in decryption. If too big this will be false
$decrypted .= $partial;
}
$decrypted = bin2hex($decrypted);
$start = strlen($decrypted) - 40;
// substr returns the new string.
$decrypted = substr($decrypted, $start);
//XML Data is Verified by SignatureValue
if ($signed_info == $decrypted) {
$result['success'] = true;
$result['uidai'] = $aadhar_id;
$result['img'] = $photo;
$result['first_name'] = strtolower(self::split_name($name)[0]);
$result['last_name'] = strtolower(self::split_name($name)[1]);
$birth_date = explode('-', $dob);
$result['birth_date'] = $birth_date[2] . '-' . $birth_date[1] . '-' . $birth_date[0];
if (strtolower($gender) === 'm') {
$result['gender'] = 'male';
} else {
$result['gender'] = 'female';
}
$result['state'] = strtolower($state);
$result['city'] = strtolower($district);
$result['address'] = strtolower($address . ', ' . $street . ', ' . $loc);
} else {
$result['error'] = 5; // Invalid signature
}
openssl_free_key($pub_key);
} else {
$result['error'] = 4; // Invalid digest
}
}
return $result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment