- 
      
 - 
        
Save ozkansari/65fa143b2018bb7c2efaf44e76d89e62 to your computer and use it in GitHub Desktop.  
| import javax.crypto.Cipher; | |
| import javax.crypto.spec.SecretKeySpec; | |
| public class EncryptSample { | |
| private static final String KEY = "AB1C11111111111AAAAAAADDDDD11111"; | |
| private static final int PIN_LENGTH = 6; | |
| public static void main(String[] args) throws Exception { | |
| TripleDES td = new TripleDES(KEY, PIN_LENGTH); | |
| String pan = "4111111111111111"; | |
| String pin = "123456"; | |
| String encrypted = td.encrypt(pan, pin); | |
| System.out.println("encrypted: " + encrypted); | |
| String decrypted = td.decrypt(pan, encrypted); | |
| System.out.println("decrypted : " + decrypted); | |
| } | |
| } | |
| class TripleDES { | |
| private static final String ALGORITHM = "TripleDES"; | |
| private static final String MODE = "ECB"; | |
| private static final String PADDING = "NoPadding"; | |
| /** algorithm/mode/padding */ | |
| private static final String TRANSFORMATION = ALGORITHM+"/"+MODE+"/"+PADDING; | |
| private final String key; | |
| private int pinLength; | |
| TripleDES(String key, int pinLength) { | |
| this.key = key; | |
| this.pinLength = pinLength; | |
| } | |
| public String encrypt(String pan, String pinClear) throws Exception { | |
| if(pinClear.length() != pinLength) { | |
| System.out.println("Incorrect PIN length given. Please fix! pinClear.size() " + "!= " + " pinLength : " + pinClear.length() + " !=" + pinLength); | |
| } | |
| String pinEncoded = encodePinBlockAsHex(pan, pinClear); | |
| byte[] tmp = h2b(this.key); | |
| byte[] key = new byte[24]; | |
| System.arraycopy(tmp, 0, key, 0, 16); | |
| System.arraycopy(tmp, 0, key, 16, 8); | |
| Cipher cipher = Cipher.getInstance(TRANSFORMATION); | |
| cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, ALGORITHM)); | |
| byte[] plaintext = cipher.doFinal(h2b(pinEncoded)); | |
| return b2h(plaintext); | |
| } | |
| public String decrypt(String pan, String encryptedPin) throws Exception { | |
| byte[] tmp = h2b(this.key); | |
| byte[] key = new byte[24]; | |
| System.arraycopy(tmp, 0, key, 0, 16); | |
| System.arraycopy(tmp, 0, key, 16, 8); | |
| Cipher cipher = Cipher.getInstance(TRANSFORMATION); | |
| cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, ALGORITHM)); | |
| byte[] plaintext = cipher.doFinal(h2b(encryptedPin)); | |
| String pinEncoded = b2h(plaintext); | |
| return decodePinBlock(pan, pinEncoded); | |
| } | |
| public String decodePinBlock(String pan, String pinEncoded) throws Exception { | |
| pan = pan.substring(pan.length() - 12 - 1, pan.length() - 1); | |
| String paddingPAN = "0000".concat(pan); | |
| byte[] pinBlock = xorBytes(h2b(paddingPAN), h2b(pinEncoded)); | |
| return b2h(pinBlock).substring(2, pinLength+2); | |
| } | |
| public String encodePinBlockAsHex(String pan, String pin) throws Exception { | |
| pan = pan.substring(pan.length() - 12 - 1, pan.length() - 1); | |
| String paddingPAN = "0000".concat(pan); | |
| String Fs = "FFFFFFFFFFFFFFFF"; | |
| String paddingPIN = "0" + pin.length() + pin + Fs.substring(2 + pin.length(), Fs.length()); | |
| byte[] pinBlock = xorBytes(h2b(paddingPAN), h2b(paddingPIN)); | |
| return b2h(pinBlock); | |
| } | |
| private static byte[] xorBytes(byte[] a, byte[] b) throws Exception { | |
| if (a.length != b.length) { | |
| throw new Exception(); | |
| } | |
| byte[] result = new byte[a.length]; | |
| for (int i = 0; i < a.length; i++) { | |
| int r = 0; | |
| r = a[i] ^ b[i]; | |
| r &= 0xFF; | |
| result[i] = (byte) r; | |
| } | |
| return result; | |
| } | |
| private static byte[] h2b(String hex) { | |
| if ((hex.length() & 0x01) == 0x01) | |
| throw new IllegalArgumentException(); | |
| byte[] bytes = new byte[hex.length() / 2]; | |
| for (int idx = 0; idx < bytes.length; ++idx) { | |
| int hi = Character.digit((int) hex.charAt(idx * 2), 16); | |
| int lo = Character.digit((int) hex.charAt(idx * 2 + 1), 16); | |
| if ((hi < 0) || (lo < 0)) | |
| throw new IllegalArgumentException(); | |
| bytes[idx] = (byte) ((hi << 4) | lo); | |
| } | |
| return bytes; | |
| } | |
| private static String b2h(byte[] bytes) { | |
| char[] hex = new char[bytes.length * 2]; | |
| for (int idx = 0; idx < bytes.length; ++idx) { | |
| int hi = (bytes[idx] & 0xF0) >>> 4; | |
| int lo = (bytes[idx] & 0x0F); | |
| hex[idx * 2] = (char) (hi < 10 ? '0' + hi : 'A' - 10 + hi); | |
| hex[idx * 2 + 1] = (char) (lo < 10 ? '0' + lo : 'A' - 10 + lo); | |
| } | |
| return new String(hex); | |
| } | |
| } | 
Thank you, amazing !
You saved my day. Thanks!
For online verification, the sessionId is used to hash the clear pin block using tripple DES → Encrypted Pin Key. For offline verification, the field for pin block can be optional.
please help me
Thanks!
You are the man!!!
This is amazing!!!
I just modified the Pinlock decode to get automatic length, based on this site https://emvlab.org/pinblock/
explaiden here https://www.linkedin.com/pulse/pinblock-explained-iftekharul-haque/
public String decodePinBlock(String pan, String pinEncoded) throws Exception {
    pan = pan.substring(pan.length() - 12 - 1, pan.length() - 1);
    String paddingPAN = "0000".concat(pan);
    byte[] pinBlock = xorBytes(h2b(paddingPAN), h2b(pinEncoded));
    //return b2h(pinBlock).substring(2, pinLength+2);
    String result=b2h(pinBlock);
    int lenClear =Integer.parseInt(result.substring(1,2)) ;
    return result.substring(2, lenClear+2);
}
So... pinLength is used to encrypt only !!!
thank you so much.
You are the man!!! This is amazing!!! I just modified the Pinlock decode to get automatic length, based on this site https://emvlab.org/pinblock/ explaiden here https://www.linkedin.com/pulse/pinblock-explained-iftekharul-haque/
public String decodePinBlock(String pan, String pinEncoded) throws Exception { pan = pan.substring(pan.length() - 12 - 1, pan.length() - 1); String paddingPAN = "0000".concat(pan); byte[] pinBlock = xorBytes(h2b(paddingPAN), h2b(pinEncoded)); //return b2h(pinBlock).substring(2, pinLength+2); String result=b2h(pinBlock); int lenClear =Integer.parseInt(result.substring(1,2)) ; return result.substring(2, lenClear+2); }So... pinLength is used to encrypt only !!!
thank you so much.
this works great thank you
Extra: https://gist.github.com/Gilmor/de2ba62407cb14b9b569