Hi am new to java card I have following data
CLA '00'
INS 'A2' nb not real value
P1 '00'
P2 '00'
LC '08'
Data In 'EF08'
Le '0D'
How can I write above instructions into bytes and send to this function? I need to get 9000 as success response and Data out.
ResponseAPDU respApdu = channel.transmit(
new CommandAPDU(cmd));
There are multiple ways to do that:
Case 1: (Not encouraged)
int cla = 0x00;
int ins = 0xA2;
int p1 = 0x00;
int p2 = 0x00;
//int LC = 0x08;'
byte[] data = new byte[] {(byte) 0xEF, (byte) 0x08};
int le = 0x0D;
ResponseAPDU respApdu = channel.transmit(
new CommandAPDU(cla, ins, p1, p2, data, le));
Case 2: (Encouraged)
byte[] apdu = new byte[] {(byte) 0x00, (byte) 0xA2, (byte) 0x00, (byte)
0x00, (byte) 0x02, (byte) 0xEF, (byte) 0x08, (byte) 0x0D};
ResponseAPDU respApdu = channel.transmit(
new CommandAPDU(apdu));
Read more about CommandAPDU and CardChannel.
Case 3: (Mostly used way)
String apdu = "00A2000002EF080D"; //also u can append strings into apdu
ResponseAPDU respApdu = channel.transmit(
new CommandAPDU(toByteArray(apdu)));
You need a Helper function:
import javax.xml.bind.DatatypeConverter;
public static byte[] toByteArray(String s) {
return DatatypeConverter.parseHexBinary(s);
}
Attention: The example APDU values you showed, LC '08' means the data will be 8 bytes long, but your data field is only 2 bytes long. So check LC again.
Related
I am currently struggling with getting a picture from a camera connected to the uart circuit of the raspberry pi. I am trying to do so with the aid of pi4j. Since I was able to initialize the camera, I do not think that the problem is related to the commands I am sending. However, when I try to open the generated .jpg the file is corrupt.
Has anyone an idea what I am doing wrong or has managed to get a picture form a camera connected to uart of the raspberry pi with java?
Camera: Grove - Serial Camera Kit
Datasheet: Grove - Serial Camera Datasheet PDF
Example Code: Python Code
private void getPicture(long pictureLength) {
try {
byte[] receiveDataPackageCommand = { (byte) 0xaa, (byte) 0x0e, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00 };
byte[] ackPackageEndCommand = { (byte) 0xaa, (byte) 0x0e, (byte) 0x00, (byte) 0x00, (byte) 0xf0,
(byte) 0xF0 };
File picture = new File(getFileName());
console.println("created file " + picture.getName());
if (picture.createNewFile()) {
FileOutputStream stream = new FileOutputStream(picture.getName());
int i = 0;
while (pictureLength > 0) {
receiveDataPackageCommand[4] = (byte) (i & 0xff);
receiveDataPackageCommand[5] = (byte) ((i >> 8) & 0xff);
serial.write(receiveDataPackageCommand);
byte[] bytes = pictureLength >= 128 ? serial.read(128) : serial.read((int) pictureLength);
stream.write(bytes);
pictureLength = pictureLength - 128;
i++;
}
stream.close();
serial.write(ackPackageEndCommand);
console.println("picture received and saved");
} else {
console.println("file already exists");
}
} catch (Exception ex) {
console.println(ex);
}
}
i am facing weak key error while doing tripleDES encryption.Code working fine in java but giving error in C# .net.
i have java code in which TripleDES ecryption is working fine i need to convert my java code in c#.i am facing Weak key error during conversion.Below both java and c# code given.
1) Java Code
public class TripleDES {
private DESedeKeySpec desKeySpec;
public TripleDES(String key) {
try {
byte[] keyBytes = { (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
(byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
(byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
(byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
(byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
(byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02};
this.desKeySpec = new DESedeKeySpec(keyBytes);
} catch (Exception e) {
e.printStackTrace();
}
}
public byte[] encrypt(byte[] origData) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(this.desKeySpec);
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(origData);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public byte[] decrypt(byte[] crypted) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(this.desKeySpec);
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding"); //DESede/CBC/PKCS5Padding
cipher.init(Cipher.DECRYPT_MODE, key);
return cipher.doFinal(crypted);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws Exception {
TripleDES des = new TripleDES("");
byte[] data = { (byte)0x04, (byte)0x12, (byte)0x05, (byte)0xFF, (byte)0xFB, (byte)0xA6, (byte)0x66, (byte)0xCF};
//byte[] data = { (byte)0x04, (byte)0x12, (byte)0x15, (byte)0xAF, (byte)0xFD, (byte)0xD8, (byte)0x88, (byte)0xBB};
//-----------------Edited-----------------
String text = new BigInteger(1, data).toString(16);
System.out.println("Before encryption = " +text);
byte[] crypted = des.encrypt(data);
String text1 = new BigInteger(1, crypted).toString(16);
System.out.println("Encrypted = " +text1);
byte[] decrypted = des.decrypt(crypted);
String text2 = new BigInteger(1, decrypted).toString(16);
System.out.println("Decrypted = " +text2);
}
}
2) C# Code
static void Main(string[] args)
{
String Data = EncryptDES("041205FFFBA666CF");
}
public static string EncryptDES(string InputText)
{
byte[] key = new byte[] { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 };
byte[] clearData = System.Text.Encoding.UTF8.GetBytes(InputText);
MemoryStream ms = new MemoryStream();
TripleDES alg = TripleDES.Create();
alg.Key = key;
alg.Mode = CipherMode.ECB;
CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(clearData, 0, clearData.Length);
cs.FlushFinalBlock();
byte[] CipherBytes = ms.ToArray();
ms.Close();
cs.Close();
string EncryptedData = Convert.ToBase64String(CipherBytes);
return EncryptedData;
}
Key: 02020202020202020202020202020202
Data : 041205FFFBA666CF
Result : A334C92CEC163D9F
Can anyone please write code in c# which produce result same as java.
Before I start, I want to say that I do not recommend or endorse you to follow this way for forcing TripleDES to use a key it thinks is weak, however, given that you are using it for Decryption only, here is a way to do it using Reflection.
Firstly, you must 'force' the TripeDES class to take the weak key you want to use. To do this, we use Reflection to bypass the check for a weak key that is performed when you attempt to set the key (alg.Key = key) and set the member variable directly:
//alg.Key = key; - THIS IS REPLACED BY THE BELOW
FieldInfo keyField = alg.GetType().GetField("KeyValue", BindingFlags.NonPublic | BindingFlags.Instance);
keyField.SetValue(alg, key);
The key value of TripleDES will now be set to your weak key (alg.Key);
Next you have a minor mistake, in that you have forgotten to turn off padding:
alg.Mode = CipherMode.ECB;
alg.Padding = PaddingMode.None; // Add this, as the default padding is PKCS7
Finally, there will be a further check for a weak key when creating the Decryptor, so we must use Reflection again to bypass the check and create the ICryptoTransform:
// Comment out the below line and use the code below
// CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
ICryptoTransform Decryptor;
MethodInfo createMethod = alg.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
Decryptor = createMethod.Invoke(alg, new object[] { alg.Key, alg.Mode, alg.IV, alg.FeedbackSize, 1 }) as ICryptoTransform;
CryptoStream cs = new CryptoStream(ms, Decryptor, CryptoStreamMode.Write);
The code will now run and accept weak keys, and perform the decryption you are looking for.
However, it does not look to me that the output is what you are expecting:
?Data
"4aU3DcHkiCTEywpiewWIow=="
At least now though you are able to use whichever key you want with TripleDES.
A 3DES key is a 24-byte value which is broken down two three 8-byte values: key0, key1, key2.
Because 3DES is DES_Encrypt(key2, DES_Decrypt(key1, DES_Encrypt(key0, data))) any time key1 is equal to key2 or key0 the algorithm is reduced to DES. This is what .NET's TripleDES is warning you about.
The proper test here should account for clearing (or setting, or fixing) the parity bits in each byte, but a hand-waved version is:
SymmetricAlgorithm alg;
IEnumerable<byte> key0 = key.Take(8);
IEnumerable<byte> key1 = key.Skip(8).Take(8);
IEnumerable<byte> key2 = key.Skip(16);
if (key0.SequenceEquals(key1))
{
alg = DES.Create();
alg.Key = key2.ToArray();
}
else if (key1.SequenceEquals(key2))
{
alg = DES.Create();
alg.Key = key0.ToArray();
}
else
{
alg = TripleDES.Create();
alg.Key = key;
}
To replace your two liner:
TripleDES alg = TripleDES.Create();
alg.Key = key;
printer : oki ml3320, emulation IBM
I can't print this barcode...
Now I took 22. example from https://files.support.epson.com/pdf/general/escp2ref.pdf
My last try looking that
final char[] x = {0x1B, 0x28, 0x42, 0x10, 0x00, 0x06, 0x02, 0x00, 0x7D, 0x00, 0x02, 0x42, 0x32, 0x33, 0x40, 0x61, 0x42, 0x63, 0x44, 0x5B, 0x5D};
if (printer.getPrinterByName("OKI")){
InputStream is = new ByteArrayInputStream(
(new String(x)).getBytes(Charset.forName(DOSCharsetProvider.MAZOVIA_CHARSET_NAME)));
Result is printed " B4}B23#aBcDC] "
For example 1. : 3}012345678012
okey got it!
char[] b = "DWZ:3:1585543:5".toCharArray();
final char[] start = {
27,16,66,
15, //length of code
66 //CODE 128 mode B
};
Last question... how Can I put a length of b to start (in 15 place)
I'm trying to sign a message on-card and verifying it off-card.
The result is always false.
I'm probably getting fetching the modulus and exponent incorrectly.
Any ideas?
Java applet code:
protected MainApplet() {
try {
// CREATE RSA KEYS AND PAIR
m_keyPair = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_1024);
// STARTS ON-CARD KEY GENERATION PROCESS
m_keyPair.genKeyPair();
// OBTAIN KEY REFERENCES
m_publicKey = (RSAPublicKey) m_keyPair.getPublic();
m_privateKey = (RSAPrivateCrtKey) m_keyPair.getPrivate();
} catch (CryptoException c) {
//this line will give you the reason of problem
short reason = c.getReason();
ISOException.throwIt(reason); // for check
}
}
.......
switch (INS) {
case 0x00:
getPublicKeyExp(apdu);
break;
case 0x10:
getPublicKeyMod(apdu);
break;
case 0x21:
signMessage(apdu);
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend((short) 0, length);
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend((short) 0, length);
}
Java host code:
/*************** EXECUTE COMMAND *************/
byte[] get_exponent = {
(byte) 0x80, // CLA Class
0x00, // INS Instruction
0x00, // P1 Parameter 1
0x00, // P2 Parameter 2
0x00 // LE maximal number of bytes expected in result
};
byte[] get_modulus = {
(byte) 0x80, // CLA Class
0x10, // INS Instruction
0x00, // P1 Parameter 1
0x00, // P2 Parameter 2
0x00 // LE maximal number of bytes expected in result
};
ResponseAPDU resp_modulus = channel.transmit(new CommandAPDU(get_modulus));
System.out.println(resp_modulus.toString());
ResponseAPDU resp_exponent = channel.transmit(new CommandAPDU(get_exponent));
System.out.println(resp_exponent.toString());
byte[] modulus = resp_modulus.getData();
byte[] exponent = resp_exponent.getData();
Code to create public key:
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(new BigInteger(1, modulus), new BigInteger(1, exponent));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
publicKey = keyFactory.generatePublic(keySpec);
Code to verify message:
byte[] get_signed_message = {
(byte) 0x80, // CLA Class
0x21, // INS Instruction
0x00, // P1 Parameter 1
0x00, // P2 Parameter 2
0x00 // LE maximal number of bytes expected in result
};
ResponseAPDU resp = channel.transmit(new CommandAPDU(get_signed_message));
System.out.println(resp.toString());
byte[] sigToVerify = resp.getData();
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(publicKey);
sig.update(sigToVerify);
boolean verifies = sig.verify(sigToVerify);
UPDATE: Java applet signature method
byte[] testSig = new byte[256];
byte[] test = {0x01, 0x02, 0x04, 0x05, 0x06, 0x07};
// CREATE SIGNATURE OBJECT
Signature m_sign = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false);
// INIT WITH PRIVATE KEY
m_sign.init(m_privateKey, Signature.MODE_SIGN);
short len = m_sign.sign(test, (short) 0, (short) test.length, testSig, (short) 0);
apdu.setOutgoing();
apdu.setOutgoingLength(len);
apdu.sendBytesLong(testSig, (short) 0, len);
The problem is in these two methods getExponent() and getModulus(). You are storing exponent and modulus into buffer's index ISO7816.OFFSET_CDATA (index 5) but sent it outside from buffer's index 0.
Compare the correct approachs with the wrong approach:
Wrong:
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend((short) 0, length); // not the valid public exp
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend((short) 0, length); // not the valid mod
}
Correct 1 (appreciated):
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, length);
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, length);
}
Correct 2:
private void getExponent(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getExponent(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, length);
}
private void getModulus(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short length = m_publicKey.getModulus(buffer, ISO7816.OFFSET_CDATA);
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, length);
}
EDIT: In your host application, you need the followings:
byte[] test = {0x01, 0x02, 0x04, 0x05, 0x06, 0x07};
sig.update(test);
boolean verifies = sig.verify(sigToVerify);
To verify a Signature, you need
a Public Key
a verification mechanism (say SHA1withRSA)
Plain Text (from which the signature was generated)
Signature
I want get the UID of the Mifare Ultralight NFC tag.
In Java I have this code:
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
System.out.println("Terminals: " + terminals);
CardTerminal terminal = terminals.get(0);
Card card = terminal.connect("*");
System.out.println("card: " + card);
CardChannel channel = card.getBasicChannel();
ResponseAPDU answer = channel.transmit(new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 0x00));
byte[] uid = answer.getBytes();
The problem is that I receive two bytes and not the UID.
What's the problem? Is the APDU correct?
The command you are actually using is not what you might have expected.
The correct command APDU to get the UID/serial number/enumeration identifier with this reader is:
+------+------+------+------+------+
| CLA | INS | P1 | P2 | Le |
+------+------+------+------+------+
| 0xFF | 0xCA | 0x00 | 0x00 | 0x00 |
+------+------+------+------+------+
However, the constructor you are using is defined as:
public CommandAPDU(int cla, int ins, int p1, int p2, int ne);
So with
new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 0x00)
you are creating a C-APDU with the following parameters CLA = 0xFF, INS = 0xCA, P1 = 0x00, P2 = 0x00. So far this is the same as the above APDU. But the last parameter is Ne = 0x00. Ne = 0 means that the number of expected response bytes is zero (whereas Le = 0 would mean that the number of expected response bytes is (up to) 256).
This results in effectively creating the following Case-1 APDU:
+------+------+------+------+
| CLA | INS | P1 | P2 |
+------+------+------+------+
| 0xFF | 0xCA | 0x00 | 0x00 |
+------+------+------+------+
So at most you will get the 2-byte status word as a response (either indicating success with 0x90 0x00 or indicating an error with a status code like 0x6X 0xXX).
So you can either use a byte array to form your APDU:
new CommandAPDU(new byte[] { (byte)0xFF, (byte)0xCA, (byte)0x00, (byte)0x00, (byte)0x00 } )
Or you can specify a proper value for Ne:
new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 256)
import java.nio.ByteBuffer;
import java.util.List;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.TerminalFactory;
public class Read {
public Read() {
try {
CardTerminal terminal = null;
// show the list of available terminals
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
String readerName = "";
for (int i = 0; i < terminals.size(); i++) {
readerName = terminals.get(i).toString()
.substring(terminals.get(i).toString().length() - 2);
//terminal = terminals.get(i);
if (readerName.equalsIgnoreCase(" 0")) {
terminal = terminals.get(i);
}
}
// Establish a connection with the card
System.out.println("Waiting for a card..");
if(terminal==null)
return;
terminal.waitForCardPresent(0);
Card card = terminal.connect("T=0");
CardChannel channel = card.getBasicChannel();
// Start with something simple, read UID, kinda like Hello World!
byte[] baReadUID = new byte[5];
baReadUID = new byte[] { (byte) 0xFF, (byte) 0xCA, (byte) 0x00,
(byte) 0x00, (byte) 0x00 };
System.out.println("UID: " + send(baReadUID, channel));
// If successfull, the output will end with 9000
// OK, now, the real work
} catch (Exception ex) {
ex.printStackTrace();
}
}
public String send(byte[] cmd, CardChannel channel) {
String res = "";
byte[] baResp = new byte[258];
ByteBuffer bufCmd = ByteBuffer.wrap(cmd);
ByteBuffer bufResp = ByteBuffer.wrap(baResp);
// output = The length of the received response APDU
int output = 0;
try {
output = channel.transmit(bufCmd, bufResp);
}` catch (CardException ex) {
ex.printStackTrace();
}`
for (int i = 0; i < output; i++) {
res += String.format("%02X", baResp[i]);
// The result is formatted as a hexadecimal integer
}
return res;
}
public static void main(String[] args) {
new Read();
}
}
After read this code For read and write purpose use bellow commands.
And Read From page : 04 to page : 07 Command is:
read_four_to_seven = new byte[]{(byte) 0xFF, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x05, (byte) 0x0D4, (byte) 0x40, (byte) 0x01,
(byte) 0x30, (byte) 0x04, (byte) 0x07 };
System.out.println("Read : " + send(read_four_to_seven, channel));
Write into Page 04:
Write_Page_Four = new byte[] { (byte) 0xFF, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x15, (byte) 0xD4, (byte) 0x40,
(byte) 0x01, (byte) 0xA0, (byte) 0x04, (byte) 0x4D,
(byte) 0x65, (byte) 0x73, (byte) 0x75, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00 };
System.out.println("Read : " + send(Write_Page_Four, channel));