Trouble writing NDEF record to NTAG213 using external NFC reader (but writing to memory works) - nfc

I am using the sample provided by Michael Roland in this answer and modified the bytes command structure to match this answer.
After I scan the tag, I receive 90 00 responses from the reader. When I then scan the tag using NFC Tools though, I don't see that it has an NDEF record (photo). If I examine the memory I can see my data written starting at block 4 as follows here.
Meanwhile, if I use the Write Tag feature of NFC Tools to write an NDEF message and then scan the tag again, it does work. The memory in the blocks other than those starting at block 4 appear to be identical (photo).
I don't believe it's a capability container issue as the memory is identical in block 3 after writing to the tag from my reader vs. NFC Tools.
Do I need to do any other kind of NDEF read / check command prior to writing to block 4?
My code below:
byte[] ndefMessage = new byte[] {
(byte)0xD1, (byte)0x01, (byte)0x0C, (byte)0x55, (byte)0x01, (byte)0x65, (byte)0x78, (byte)0x61, (byte)0x6D, (byte)0x70, (byte)0x6C, (byte)0x65, (byte)0x2E, (byte)0x63, (byte)0x6F, (byte)0x6D, (byte)0x2F
};
// wrap into TLV structure
byte[] tlvEncodedData = null;
Log.e("length",String.valueOf(ndefMessage.length));
if (ndefMessage.length < 255) {
tlvEncodedData = new byte[ndefMessage.length + 3];
tlvEncodedData[0] = (byte)0x03; // NDEF TLV tag
tlvEncodedData[1] = (byte)(ndefMessage.length & 0x0FF); // NDEF TLV length (1 byte)
System.arraycopy(ndefMessage, 0, tlvEncodedData, 2, ndefMessage.length);
tlvEncodedData[2 + ndefMessage.length] = (byte)0xFE; // Terminator TLV tag
} else {
tlvEncodedData = new byte[ndefMessage.length + 5];
tlvEncodedData[0] = (byte)0x03; // NDEF TLV tag
tlvEncodedData[1] = (byte)0xFF; // NDEF TLV length (3 byte, marker)
tlvEncodedData[2] = (byte)((ndefMessage.length >>> 8) & 0x0FF); // NDEF TLV length (3 byte, hi)
tlvEncodedData[3] = (byte)(ndefMessage.length & 0x0FF); // NDEF TLV length (3 byte, lo)
System.arraycopy(ndefMessage, 0, tlvEncodedData, 4, ndefMessage.length);
tlvEncodedData[4 + ndefMessage.length] = (byte)0xFE; // Terminator TLV tag
}
// fill up with zeros to block boundary:
tlvEncodedData = Arrays.copyOf(tlvEncodedData, (tlvEncodedData.length / 4 + 1) * 4);
for (int i = 0; i < tlvEncodedData.length; i += 4) {
byte[] command = new byte[] {
(byte)0xFF, // WRITE
(byte)0xD6,
(byte)0x00,
(byte)((4 + i / 4) & 0x0FF), // block address
(byte)0x04,
0, 0, 0, 0
};
System.arraycopy(tlvEncodedData, i, command, 5, 4);
ResponseAPDU answer = cardChannel.transmit(new CommandAPDU(command));
byte[] response = answer.getBytes();
writeLogWindow("response: "+ byteArrayToHexString(response));
}

I believe that the problem is that Michael Roland's answer has a bug in it.
D1 01 0C 55 01 65 78 61 6D 70 6C 65 2E 63 6F 6D 2F is not a valid Ndef message.
If you look at the various specs for Ndef at https://github.com/haldean/ndef/tree/master/docs (specifically the NFCForum-TS-RTD_URI_1.0.pdf and NFCForum-TS-NDEF_1.0.pdf) his example of "http://www.example.com/" is actually made up of "http://www." which has a type code of 01 and 12 characters or the rest of the URL.
Thus the payload length is 13 (1 + 12) bytes so OD where as his message:-
D1 01 0C 55 01 65 78 61 6D 70 6C 65 2E 63 6F 6D 2F
only specifies the length of the second part of the URL and not the prefix, so is one byte too short.
This is confirmed if you try and write a record for that URL using the NFC Tools App or NXP's TagWriter App both generate a message of
D1 01 0D 55 01 65 78 61 6D 70 6C 65 2E 63 6F 6D 2F
So try using in your code
byte[] ndefMessage = new byte[] {
(byte)0xD1, (byte)0x01, (byte)0x0D, (byte)0x55, (byte)0x01, (byte)0x65, (byte)0x78,
(byte)0x61, (byte)0x6D, (byte)0x70, (byte)0x6C, (byte)0x65, (byte)0x2E, (byte)0x63,
(byte)0x6F, (byte)0x6D, (byte)0x2F
};

Related

A Very Strange phenomenon when decrypt aes-128-gcm tls package using OpenSSL in ruby

I'm implimenting my own ssl/tls library for learning purpose. These days when I seed encrypted message to server, I will a receive "bad mac" alert. Today I use this question's record to debug my code.
This is where the strange thing happend. I use his server_random, client_random and master-secret to generate client_write_key and client_write_iv. Then I get the same output as his. However, when I use the client_wrtie_key and client_write_iv to decrypt the "GET / HTTP/1.0\n" message, I get this output:
Q▒W▒ ▒7▒3▒▒▒
This is so different from the correct message! My whole debug output is
C:/Users/ayanamists/.babun/cygwin/home/ayanamists/my_ssl_in_ruby/encrypt_handler/aes_gcm_handler.rb:87:in `final': OpenSSL::Cipher::CipherError
from C:/Users/ayanamists/.babun/cygwin/home/ayanamists/my_ssl_in_ruby/encrypt_handler/aes_gcm_handler.rb:87:in `recv_decrypt'
from decrypt.rb:72:in `<main>'
client write key is
4b 11 9d fb fc 93 0a be 13 00 30 bd 53 c3 bf 78
nonce is
20 29 ca e2 c9 1d e0 05 e2 ae 50 a8
what to be decrypt:
a5 7a be e5 5c 18 36 67 b1 36 34 3f ee f4 a3 87 cb 7c f8 30 30
the tag is
a4 7e 23 0a f2 68 37 8c 4f 33 c8 b5 ba b3 d2 6d
the additional data is
00 00 00 00 00 00 00 01 17 03 03 00 00 15
decrypter is
OpenSSL::Cipher::AES
Q▒W▒ ▒7▒3▒▒▒
output is
bd 8c e8 87 b7 ab c6 f7 eb 31 fd cb 65 4c d4 a9 16 ae 1b ca da
the correct is
47 45 54 20 2f 20 48 54 54 50 2f 31 2e 30 0a
You can see that my key and nonce have no different with his key and nonce, but why the result is wrong?
The code is:
require_relative 'encrypt_message_handler'
require 'pp'
class AES_CGM_Handler
include EncryptMessageHandler
attr_accessor :send_cipher, :recv_cipher, :send_implicit, :recv_implicit,
:send_seq_num, :recv_seq_num
def initialize(server_random, client_random, certificate = '', length = 0,
usage = 'client', version_major = 0x03, version_minor = 0x03)
if block_given?
#master = yield
#version = [0x03, 0x03]
else
super(server_random, client_random, certificate)
end
# the nonce of AES_GCM is defined by:
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# + 0 1 2 3 | 0 1 2 3 4 5 6 7 +
# + salt | nonce_explicit +
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# salt is server_write_iv or client_write_iv, so you need 4 * 2
# and length need to /8(bit->byte) and * 2(both server and client), so it's length/4
key_block = (length/4 + 4 * 2).tls_prf(#master, "key expansion", server_random + client_random)
arr = key_block.unpack "a#{length/8}a#{length/8}a4a4"
client_write_key = arr[0]
server_write_key = arr[1]
client_write_iv = arr[2]
server_write_iv = arr[3]
#send_cipher = OpenSSL::Cipher::AES.new(length, :GCM).encrypt
#recv_cipher = OpenSSL::Cipher::AES.new(length, :GCM).decrypt
if usage == 'client'
#send_cipher.key = client_write_key
#send_implicit = client_write_iv
#recv_cipher.key = server_write_key
#recv_implicit = server_write_iv
puts "server write key is #{server_write_key.to_hex}"
elsif usage == 'server'
#send_cipher.key = server_write_key
#send_implicit = server_write_iv
#recv_cipher.key = client_write_key
#recv_implicit = client_write_iv
puts "client write key is\n #{client_write_key.to_hex}"
else
raise "AES_GCM_HANDLER: BAD_ARGUMENT"
end
#send_seq_num = 0
#recv_seq_num = 0
end
def send_encrypt(type = 22, seqence = '')
nonce_explicit = OpenSSL::Random.random_bytes(8)
nonce = #send_implicit + nonce_explicit
#send_cipher.iv = nonce
length = seqence.length
#the handle of seq_num may be wrong
#send_cipher.auth_data = [0, #send_seq_num,
type, #version[0], #version[1], 0 ,length].pack("NNCCCCn")
encrypt = #send_cipher.update(seqence) + #send_cipher.final
encrypt = encrypt + #send_cipher.auth_tag
return encrypt
end
def recv_decrypt(type = 22, sequence = '', seq_num = 0)
if seq_num != 0
#recv_seq_num = seq_num
end
template = 'a8a*'
arr = sequence.unpack(template)
nonce_explicit = arr[0]
length = sequence.length - 8 - 16
sequence = arr[1]
encrypted = sequence[0, sequence.length - 16]
#recv_cipher.auth_tag = sequence[sequence.length - 16, sequence.length]
#recv_cipher.iv = #recv_implicit + nonce_explicit
puts "nonce is\n #{(#recv_implicit + nonce_explicit).to_hex}"
puts "what to be decrypt: \n #{encrypted.to_hex}"
puts "the tag is \n #{sequence[sequence.length - 16, sequence.length].to_hex}"
#recv_cipher.auth_data =
[0, #recv_seq_num, type ,#version[0], #version[1], 0 ,length].pack("NNCCCCn")
puts "the additional data is\n #{([0, #recv_seq_num, type ,#version[0], #version[1], 0 ,length].pack("NNCCCCn")).to_hex }"
puts "decrypter is\n #{#recv_cipher.class}"
puts #recv_cipher.update(encrypted)
puts "output is\n #{#recv_cipher.update(encrypted).to_hex}"
puts "the correct is\n #{"GET / HTTP/1.0\n".to_hex}"
decrypt = #recv_cipher.update(encrypted) + #recv_cipher.final
return decrypt
end
end
Please help me to solve this problem, I'll be very grateful!
I have solved this question eventually!
If anyone want to use this test vector, do not forget to add "789c" as zlib compress

how to find xor key/algorithm, for a given hex?

So i have this hex: B0 32 B6 B4 37
I know this hex is obfuscated with some key/algorithm.
I also know this hex is equal to: 61 64 6d 69 6e (admin)
How can i calculate the XOR key for this?
If you write out the binary representation, you can see the pattern:
encoded decoded
10110000 -> 01100001
00110010 -> 01100100
Notice that the bit patterns have the same number of bits before and after. To decode, you just bitwise rotate one bit left. So the value shifts left one place and the most significant bit wraps around to the least significant place. To encode, just do the opposite.
int value, encoded_value;
encoded_value = 0xB0;
value = ((encoded_value << 1) | (encoded_value >> 7)) & 255;
// value will be 0x61;
encoded_value = ((value >> 1) | (value << 7)) & 255;

fail to correctly encode and decode using java.util.Base64

Let "awids" be 12 characters length ids in base 64 (A-Z a-z 0-9 "-" "#"). This is the input.
My final goal is to create a bijective mapping between these awids and UUIDs, using some paddings, having as initial input the awids.
While trying to use java.util.Base64 I do not get the initial value after a decoding and an encoding again. What is the stupid error I do? :)
With the reproducible example I present below the output is wrong because the input string is not gotten back after a decode()-encode() and the bijection is not preserved (Q39s/L and Q39s/A map both to the same value).
------------------------------------------> Q39s/L (6 [51 33 39 73 2f 4c])
4 [43 7f 6c fc] -> 6 [51 33 39 73 2f 41] -> Q39s/A (6 [51 33 39 73 2f 41])
4 [43 7f 6c fc] -> 6 [51 33 39 73 2f 41] -> Q39s/A (6 [51 33 39 73 2f 41])
Here a is a reproducible example:
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.StringJoiner;
public class StackOverflowQuestion {
public static void main(String[] args) {
String halfAwid = "Q39s/L";
byte[] sigBits = Base64.getDecoder().decode(halfAwid.getBytes(StandardCharsets.UTF_8));
byte[] actualSigBits = Base64.getEncoder().withoutPadding().encode(sigBits);
String actualHalfAwid = new String(actualSigBits, StandardCharsets.UTF_8);
byte[] sigBits2 = Base64.getDecoder().decode(halfAwid.getBytes(StandardCharsets.UTF_8));
byte[] actualSigBits2 = Base64.getEncoder().withoutPadding().encode(sigBits2);
String actualHalfAwid2 = new String(actualSigBits2, StandardCharsets.UTF_8);
System.out.println("----------------------------------------------> "
+ halfAwid + " (" + toHexString(halfAwid) + ") "
+ "\n"
+ " "
+ toHexString(sigBits) + " -> "
+ toHexString(actualSigBits) + " -> "
+ actualHalfAwid + " (" + toHexString(actualHalfAwid) + ") "
+ "\n"
+ " "
+ toHexString(sigBits2) + " -> "
+ toHexString(actualSigBits2) + " -> "
+ actualHalfAwid2 + " (" + toHexString(actualHalfAwid2) + ")"
+ "");
}
private static String toHexString(byte[] bytes) {
StringJoiner joiner = new StringJoiner(" ", "" + bytes.length + " [", "]");
for (byte b : bytes) {
joiner.add(String.format("%02x", b));
}
return joiner.toString();
}
private static String toHexString(String text) {
return toHexString(text.getBytes());
}
}
Do not hesitate to point any other errors I do in the code, even if they are not related directly to the question. Thank you.
The Base64 encoding is not a bijective mapping for all input sizes, if you treat the encoded data as a sequence of whole bytes (or ASCII characters). Base64 is encoding units of eight bits to units of six bits (yielding 64 possible combinations for each unit), so when you encode four bytes, in other words 4×8=32 bits, you will get 32/6=5⅓ units output, which implies that the sixth unit of the output will not use all bits.
In other words, when you treat an arbitrary string consisting of six of the 64 defined characters as being Base64 encoded, you will project a string of 64⁶ combinations to a “source” sequence of six bytes having 256⁴ combinations, which implies a data loss.
You can use Base64 encoding as a bijective mapping if you choose input sizes which can be projected to a whole number of units, e.g. obviously six source bytes can be encoded as eight Base64 encoded bytes. But it doesn’t work for six encoded bytes. Interestingly, it will work for your actually desired size as nine source bytes will get encoded to exactly twelve encoded bytes: 9×8=72, 72/6=12.

modify json file using cJSON library

what i want to do is reading a json format file and modify it then writing the modified content to file.
55 cJSON *root,*basicpara;
56 char *out;
57
58 root = dofile("basicparameter.cfg");
59 out = cJSON_Print(root);
60 printf("before modify:%s\n",out);
61 free(out);
62 basicpara = cJSON_GetObjectItem(root,"basicparameter");
63 cJSON_GetObjectItem(basicpara,"mode")->valueint = 0;
64 cJSON_GetObjectItem(basicpara,"TimeoutPoweron")->valueint = 10;
65
66 out = cJSON_Print(root);
67 printf("after modify:%s\n",out);
68 free(out);
69 //write_file("basicparameter.cfg",out);
70 cJSON_Delete(root);
i am confused why both contents are the same...
before modify:{
"basicparameter": {
"mode": 1,
"nBefore": 2,
"nAfter": 2,
"LuxAutoOn": 50,
"LuxAutoOff": 16,
"TimeoutPoweron": 30
}
}
after modify:{
"basicparameter": {
"mode": 1,
"nBefore": 2,
"nAfter": 2,
"LuxAutoOn": 50,
"LuxAutoOff": 16,
"TimeoutPoweron": 30
}
}
Please use the cJSON_SetNumberValue macro for setting the number. The problem is, that you are only setting the valueint property but printing relies on the valuedouble property.
Having both valueint and valuedouble in cJSON was a terrible design decision and will probably confuse many people in the future as well.

Is there any good and stable online SMS to PDU converter?

I'm looking for a nice online converter which could work with several modems. The problem i'm dealing with - i can't send sms in pdu mode (with Cinterion BGS-2T). Tried with my own library (still working on it) and several online converters such as:
http://www.smartposition.nl/resources/sms_pdu.html
http://m2msupport.net/m2msupport/module-tester/
http://hardisoft.ru/soft/otpravka-sms-soobshhenij-v-formate-pdu-teoriya-s-primerami-na-c-chast-1/
User data seems to be encoded well (same result everywhere), but the first part of TPDU (with PDU-Type, TP-MR, ...) may be a little bit variable (but never works, damn).
Few moments:
The modem definitely supports pdu mode.
There is cash on balance.
Modem responses on "AT+CMGS" with ">" and it responses on PDU string with "\r\nOK\r\n", but didn't responds with "+CMGS" (and of course i'm not receiving my sms).
If it necessary here is part of my own code:
void get_pdu_string(sms_descriptor* sms, char dst[]) {
char tempnum[8] = "";
char* pTemp = dst;
uint8_t i = 0;
// SMSC
//*pTemp++ = 0x00;
// PDU-Type
*pTemp++ = (0<<TP_MTIH) | (1<<TP_MTIL); // MTI = 01 - outbox sms
// TP-MR
*pTemp++ = 0x00; // unnecessary
// TP-DA
*pTemp++ = strlen(sms->to_number); // address number length
*pTemp++ = 0x91; // address number format (0x91 - international)
gsm_number_swap(sms->to_number,tempnum);
i = (((*(pTemp-2) & 0x01) == 0x01)? (*(pTemp-2)+1) : *(pTemp-2))>>1;
strncpy(pTemp, tempnum, i ); // address number
pTemp += i;
// TP-PID
*pTemp++ = 0;
// TP-DCS
switch(sms->encoding) {
case SMS_7BIT_ENC:
*pTemp++ = 0x00;
break;
case SMS_UCS2_ENC:
*pTemp++ = 0x08;
break;
}
if (sms->flash == 1)
*(pTemp-1) |= 0x10;
// TP-VP
// skip if does not need
// TP-UDL
switch(sms->encoding) {
case SMS_7BIT_ENC:
*pTemp++ = strlen(sms->msg);
break;
case SMS_UCS2_ENC:
*pTemp++ = strlen(sms->msg) << 1;
break;
}
// TP-UD
switch(sms->encoding) {
case SMS_7BIT_ENC: {
char packed_msg[140] = "";
char* pMsg = packed_msg;
gsm_7bit_enc(sms->msg, packed_msg);
while(*pMsg != 0)
*pTemp++ = *pMsg++;
} break;
case SMS_UCS2_ENC: {
wchar_t wmsg[70] = L"";
wchar_t* pMsg = wmsg;
strtoucs2(sms->msg, wmsg, METHOD_TABLE);
while(*pMsg != 0) {
*pTemp++ = (char) (*pMsg >> 8);
*pTemp++ = (char) (*pMsg++);
}
} break;
}
*pTemp = 0x1A;
return;
}
Example of my routine work:
To: 380933522620
Message: Hello! Test SMS in GSM-7
Encoded PDU string:
00 01 00 0C 81 83 90 33 25 62 02 00 00 18 C8 32 9B FD 0E 81 A8 E5 39 1D 34 6D 4E 41 69 37 E8 38 6D B6 6E 1A
Details about PDU string:
1. 00 - skipped SMSC
2. 01 - PDU-Type
3. 00 - TP-MR
4. 0C - length of To number.
5. 81 - type of number (unknown, also tried 0x91 which is international)
6. 83 90 33 25 62 02 - To number
7. 00 - TP-PID
8. 00 - TP-DCS (GSM 7bit, default SMS class)
9. 18 - TP-UD (24 letters)
10. C8 32 ... B6 6E - packed message
11. 1A - ctrl+z
Problem is fixed. I was sending message not as hex string but as binary, silly me :(
I've created balance checker for my openwrt routers. It is written in C and very simple. Works fine for velcom.by and mts.by.

Resources