I am developing a software for EMV transactions and I am facing a huge lack of documentation from the company who has hired me.
One of them is about the MKD for generating the ARQC (during the first GENERATE AC). I know from the message request that the IAD is as below:
0FA501A030F8000000000000000000000F000000000000000000000000000000
According to it the Cryptogram Version is 5, but I have no idea about the MKD.
Does anyone who has been involved in this subject know something about the MKD I should use to generate ARQC ?
I´d appreciate any comments.
Thanks.
(In context of vanilla EMV and Common Core Specifications)
Citing EMV 4.3, Book 2, section 8.1.2:
The method for Application Cryptogram generation takes as input a
unique ICC Application Cryptogram Master Key MKAC and the data
selected as described in section 8.1.1, and computes the 8-byte
Application Cryptogram in the following two steps:
Use the session key derivation function specified in Annex A1.3 to derive an Application Cryptogram Session Key SKAC from the ICC
Application Cryptogram Master Key MKAC and the 2-byte Application
Transaction Counter (ATC) of the ICC.
Generate the 8-byte Application Cryptogram by applying the MAC algorithm specified in Annex A1.2 to the data selected and using the
Application Cryptogram Session Key derived in the previous step. For
AES the 8-byte Application Cryptogram is created by setting the
parameter s to 8.
The MKAC itself is derived from 'Issuer (Application Cryptogram) Master Key' (section 8.3):
For a cryptogram defined by the Common Core Definitions with a
Cryptogram Version of '5', the ICC Master Key shall be derived using
the Option B method described in Annex A1.4.2.
See the mentioned annexes of EMV Book 2 for detailed descriptions.
I can provide the following java code (semi-tested but without any guarantees):
public static byte[] deriveMasterKey(byte[] issuerMasterKey, byte[] pan, byte[] panSequenceNumber) {
String concat;
if(((pan[pan.length-1]&0x0F)==0x0F)) {
String help=ByteArrayUtils.toString(pan);
concat = "0" + help.substring(0, help.length()-1) + ByteArrayUtils.toString(panSequenceNumber);
} else {
concat = ByteArrayUtils.toString(pan) + ByteArrayUtils.toString(panSequenceNumber);
}
logger.debug("Concat: " + concat);
byte[] concatBytes=ByteArrayUtils.fromSafeString(concat);
byte[] sha1Bytes = SwCryptUtils.sha1(concatBytes);
String sha1=ByteArrayUtils.toString(sha1Bytes);
logger.debug("X: " + sha1);
StringBuilder b1 = new StringBuilder();
StringBuilder b2 = new StringBuilder();
for(char c : sha1.toCharArray()) {
if(Character.isDigit(c)) {
b1.append(c);
} else {
b2.append((char)(c-('A'-'0')));
}
}
String y = b1.toString() + b2.toString();
logger.debug("Y': " + y);
y = y.substring(0, 16);
logger.debug("Y: " + y);
byte[] yBytes = ByteArrayUtils.fromSafeString(y);
byte[] leftBytes = SwCryptUtils.desEncryptEcb(issuerMasterKey, yBytes);
String left = ByteArrayUtils.toString(leftBytes);
logger.debug("Z_{L}': " + left);
byte[] yXorBytes = yBytes.clone();
for (int i = 0; i < yXorBytes.length; i++) {
yXorBytes[i]^=0xFF;
}
logger.debug("Y_{xor}': " + ByteArrayUtils.toString(yXorBytes));
byte[] rightBytes = SwCryptUtils.desEncryptEcb(issuerMasterKey, yXorBytes);
String right = ByteArrayUtils.toString(rightBytes);
logger.debug("Z_{R}': " + right);
String result=left+right;
logger.debug("MK:" + result);
return ByteArrayUtils.fromSafeString(result);
}
public static byte[] deriveCommonSessionKey(byte[] masterKey, byte[] atc) {
byte[] rBytes=Arrays.copyOf(atc, 8);
logger.debug("R: " + ByteArrayUtils.toString(rBytes));
byte[] f1Bytes=rBytes.clone();
f1Bytes[2]=(byte)0xF0;
logger.debug("F1: " + ByteArrayUtils.toString(f1Bytes));
byte[] f2Bytes=rBytes.clone();
f2Bytes[2]=(byte)0x0F;
logger.debug("F2: " + ByteArrayUtils.toString(f2Bytes));
byte[] f1EncBytes = SwCryptUtils.desEncryptEcb(masterKey, f1Bytes);
logger.debug("ENC(F1): " + ByteArrayUtils.toString(f1EncBytes));
byte[] f2EncBytes = SwCryptUtils.desEncryptEcb(masterKey, f2Bytes);
logger.debug("ENC(F2): " + ByteArrayUtils.toString(f2EncBytes));
byte[] result = ArrayUtils.addAll(f1EncBytes, f2EncBytes);
logger.debug("SK: " + ByteArrayUtils.toString(result));
return result;
}
public static byte[] generateApplicationCryptogram(byte[] sessionKey, byte[] terminalData, byte[] iccData) {
byte[] dataBytes = ArrayUtils.addAll(terminalData, iccData);
logger.debug("DATA: " + ByteArrayUtils.toString(dataBytes));
byte[] paddedDataBytes = ArrayUtils.add(dataBytes, (byte)0x80);
paddedDataBytes=Arrays.copyOf(paddedDataBytes, ((paddedDataBytes.length+7)/8)*8);
logger.debug("PADDED DATA: " + ByteArrayUtils.toString(paddedDataBytes));
byte[] skBytes=sessionKey;
byte[] skL = Arrays.copyOf(skBytes, 8);
logger.debug("SK_{L}: " + ByteArrayUtils.toString(skL));
byte[] skR = Arrays.copyOfRange(skBytes, 8, 16);
logger.debug("SK_{R}: " + ByteArrayUtils.toString(skR));
byte[] pom = SwCryptUtils.desEncryptCbcZeroIv(skL, paddedDataBytes);
logger.debug("POM: " + ByteArrayUtils.toString(pom));
pom=Arrays.copyOfRange(pom, pom.length-8, pom.length);
logger.debug("POM: " + ByteArrayUtils.toString(pom));
pom=SwCryptUtils.desDecryptEcb(skR, pom);
logger.debug("POM: " + ByteArrayUtils.toString(pom));
pom=SwCryptUtils.desEncryptEcb(skL, pom);
logger.debug("POM: " + ByteArrayUtils.toString(pom));
logger.debug("AC: " + ByteArrayUtils.toString(pom));
return pom;
}
A very good source of information is the EFTlab website (their BP-CCalc tool can used to compute keys, cryptograms...).
Good luck!
Related
I am trying to understand the address system in the plac4x java implementation. Below an example of the reading code of the plcs:
#Test
void testReadingFromPlc() {
// Establish a connection to the plc using the url provided as first argument
try( PlcConnection plcConnection = new PlcDriverManager().getConnection( "modbus:tcp://1.1.2.1" ) ){
// Create a new read request:
// - Give the single item requested the alias name "value"
var builder = plcConnection.readRequestBuilder();
builder.addItem( "value-" + 1, "register:1[9]" );
builder.addItem( "value-" + 2, "coil:1000[8]" );
var readRequest = builder.build();
LOGGER.info( "Synchronous request ..." );
var syncResponse = readRequest.execute().get();
// Simply iterating over the field names returned in the response.
var bytes = syncResponse.getAllByteArrays( "value-1" );
bytes.forEach( item -> System.out.println( TopicsMapping.byteArray2IntegerArray( item )[0] ) );
var booleans = syncResponse.getAllBooleans( "value-2" );
booleans.forEach( System.out::println );
}catch(Exception e){
e.printStackTrace();
}
}
Our PLCs manage 16 registers, but the regex of the addresses don't allow to have a quantity bigger than 9. Is it possible to change this?
Moreover, if I try to add an other field with the same purpose then no reading happen:
var builder = plcConnection.readRequestBuilder();
builder.addItem( "value-" + 0, "register:26[8]" );
builder.addItem( "value-" + 1, "register:34[8]" );
builder.addItem( "value-" + 2, "coil:1000[8]" );
var readRequest = builder.build();
Any help much appreciated. Could you also show me where I can find more information on this framework?
I am reading and writing using the modbus driver in PLC4x with success. I have attached some writing code to your other question at: Plc4x addressing system
About reading, here is some code:
public static PlcReadResponse readModbusTestData(ProtocolClient client,
String registerName,
int offset,
int size,
String registerType)
throws ExecutionException, InterruptedException, TimeoutException {
PlcReadRequest readRequest = client.getConnection().readRequestBuilder()
.addItem(registerName, registerType + ":" + offset + "[" + size + "]").build();
return readRequest.execute().get(2, TimeUnit.SECONDS);
}
The multiple read adding more items to the PlcReadRequest has not been tested yet by me, but it should work. Writing several items is working.
In any case, in order to understand how PLC4x works for modbus or opc-ua I have needed to dive into the source code. It works, but you need to read the source code for the details at its current state.
I need some help in understanding, how to decrypt SalesforceMarketingCloud encrypted String into java.
I should admit that I have few things missing in my questions but this is what ever I have been provided so far
Algorithm – AES256, 256 Bit
Initilization vector – 16 bytes
Salt – 8 Bytes
Passphrase – “presharedpassphrase123”
As per my understanding the Input String has been encrypted using
EncryptSymmetric(#Clear, "AES", #null, #Passphrase, #null, #Salt, #null, #IV)
But when I try to decrypt it at Java side, it fails for various reason.
My best shot has been getting a garbage String as output so far when I used combination like below
NoPadding, CBS, and hashing my passphrase(which is 22 char long) to 32 bit using SHA-256
Can anyone please help, any Java code sample which you successfully used in past.
private String decryptWithKey(String myKey, byte[] strToDecrypt) throws Exception
{
MessageDigest sha = null;
try {
key = myKey.getBytes(CHAR_SCHEME);
sha = MessageDigest.getInstance("SHA-256");
key = sha.digest(key);
key = Arrays.copyOf(key, 32);
secretKey = new SecretKeySpec(key, ALGO);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
byte[] ivByte = new byte[cipher.getBlockSize()];
ivByte = hexStringToByteArray("0716A494177F29F102AF33AFD0253BA1");;
System.out.println(new String(ivByte));
// IvParameterSpec ivParamsSpec = new IvParameterSpec(IV);
IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParamsSpec);
setDecryptedString(new String(cipher.doFinal(strToDecrypt)));
}
catch (Exception e)
{
System.out.println("Error while decrypting: "+e.toString());
throw e;
}
return decryptedString;
}
Trying to Construct a Shared Access Signature URI for a Blob access in a container
BlobHelper BlobHelper = new BlobHelper(StorageAccount, StorageKey);
string signature = "";
string signedstart = DateTime.UtcNow.AddMinutes(-1).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'");
string signedexpiry = DateTime.UtcNow.AddMinutes(2).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'");
//// SET CONTAINER LEVEL ACCESS POLICY
string accessPolicyXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<SignedIdentifiers>\n" +
" <SignedIdentifier>\n" +
" <Id>twominutepolicy</Id>\n" +
" <AccessPolicy>\n" +
" <Start>" + signedstart + "</Start>\n" +
" <Expiry>" + signedexpiry + "</Expiry>\n" +
" <Permission>r</Permission>\n" +
" </AccessPolicy>\n" +
" </SignedIdentifier>\n" +
"</SignedIdentifiers>\n";
BlobHelper.SetContainerAccessPolicy("xxxxxxx", "container", accessPolicyXml));
string canonicalizedresource = "/xxxxxxx/501362787";
string StringToSign = String.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}\n{8}\n{9}\n{10}",
"r",
signedstart,
signedexpiry,
canonicalizedresource,
"twominutepolicy",
"2013-08-15",
"rscc",
"rscd",
"rsce",
"rscl",
"rsct"
);
using (HMACSHA256 hmacSha256 = new HMACSHA256(Convert.FromBase64String(StorageKey)))
{
Byte[] dataToHmac = System.Text.Encoding.UTF8.GetBytes(StringToSign);
signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac));
}
StringBuilder sasToken = new StringBuilder();
sasToken.Append(BlobHelper.DecodeFrom64(e.Item.ToolTip).ToString().Replace("http","https") + "?");
//signedversion
sasToken.Append("sv=2013-08-15&");
sasToken.Append("sr=b&");
//
sasToken.Append("si=twominutepolicy&");
sasToken.Append("sig=" + signature + "&");
//
sasToken.Append("st=" + HttpUtility.UrlEncode(signedstart).ToUpper() + "&");
//
sasToken.Append("se=" + HttpUtility.UrlEncode(signedexpiry).ToUpper() + "&");
//
sasToken.Append("sp=r");
string url = sasToken.ToString();
I am getting the following exception below
<Error>
<Code>AuthenticationFailed</Code>
<Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:e424e1ac-fd96-4557-866a-992fc8c41841 Time:2014-05-22T18:46:15.3436786Z</Message>
<AuthenticationErrorDetail>Signature did not match. String to sign used was r 2014-05-22T18:45:06Z 2014-05-22T18:48:06Z /xxxxxxx/501362787/State.SearchResults.pdf twominutepolicy 2013-08-15 </AuthenticationErrorDetail>
</Error>
rscc, rscd, rsce, rscl, rsct are placeholders for overridden response headers. Your sasToken variable does not seem to override response headers, so you should just use empty strings with a new-line character when signing them. Moreover, it looks like your canonicalized resource also does not match the server's resource.
By the way, did you look at Azure Storage Client Library to create Shared Access Signature tokens? It provides lots of features and is the official SDK to access Microsoft Azure Storage.
The following is code I have used to try to record skeleton frame data
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame == null)
return;
this.Recorder.Record(skeletonFrame);
}
if the code above is run, what information is recorded?
If I were to save this information to an external file, what would I see?
Would there be coordinate information and a specific timestamp associated with each coordinate information?
Are you looking at recording the X, Y, Z data of the skeleton into a text file? It is generally easier to record the information separately in readable format. If you are looking at doing the aforementioned then this may help:
//save the XYZ of the skeleton data, but also save the XZ of depth data
private void saveCoordinates(Skeleton skeleton, string textFile)
{
StreamWriter coordinatesStream = new StreamWriter(newPath + "\\" + textFile);
foreach (Joint joint in skeleton.Joints)
{
coordinatesStream.WriteLine(joint.JointType + ", " + joint.TrackingState + ", " + joint.Position.X + ", " + joint.Position.Y + ", " + joint.Position.Z);
}
coordinatesStream.Close();
}
Is there any way to force Hudson to give me more detailed test results - e.g. I'm comparing two strings and I want to know where they differ.
Is there any way to do this?
Thank you for help.
You should not hope Hudson give the detail information, it just shows the testing messages generated by junit.
You could show the expected string and actual string when failing asserting equals between those two strings.
For example,
protected void compareFiles(File newFile, String referenceLocation, boolean lineNumberMatters) {
BufferedReader reader = null;
BufferedReader referenceReader = null;
List<String> expectedLines = new ArrayList<String>();
try {
referenceReader = new BufferedReader(new InputStreamReader(FileLocator.openStream(Activator.getDefault().getBundle(), new Path("data/regression/" + referenceLocation), false))); //$NON-NLS-1$
expectedLines = getLinesFromReader(referenceReader);
} catch (Exception e) {
assertFalse("Exception occured during reading reference data: " + e, true); //$NON-NLS-1$
}
List<String>foundLines = new ArrayList<String>();
try {
reader = new BufferedReader(new FileReader(newFile));
foundLines = getLinesFromReader(reader);
} catch (Exception e) {
assertFalse("Exception occured during reading file: " + e, true); //$NON-NLS-1$
}
boolean throwException = expectedLines.size() != foundLines.size();
if (throwException) {
StringBuffer buffer = new StringBuffer("\n" + newFile.toString()); //$NON-NLS-1$
for (String line: foundLines)
buffer.append(line + "\n"); //$NON-NLS-1$
assertEquals("The number of lines in the reference(" + referenceLocation + ") and new output(" + newFile.getAbsolutePath()+ ") did not match!" + buffer, expectedLines.size(), foundLines.size()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if (!lineNumberMatters) {
Collections.sort(expectedLines);
Collections.sort(foundLines);
}
/** Either the line matches character by character or it matches regex-wise, in that order */
for (int i=0;i<expectedLines.size(); i++)
assertTrue("Found errors in file (" + newFile + ")! " + foundLines.get(i) + " vs. " + expectedLines.get(i), foundLines.get(i).equals(expectedLines.get(i)) || foundLines.get(i).matches(expectedLines.get(i))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
Hudson supports JUnit directly. On your job configuration page, near the end, should be an option to "Publish JUnit test results report".
I'm not too familiar with JUnit itself, but I guess it produces (or has the ability to produce) and put results in an xml file. You just need to put the path of to the xml file (relative to the workspace) in the text box.
Once you do that, and create a build, you'll have a detailed report on your project page. You should then be able to click your way through the results for each test.