Based on this article: https://www.linkedin.com/pulse/card-verification-code-cvc-value-cvv-nayoon-cooray CVV is possible calculate according to the next values and parameters:
Calculating the CVV1, CVV2, iCVV
1. Concatenate the PAN, expiry date and service code and pad right with zeros to get 16-bytes (32 Hexadecimal string) key value
4123121234567891 + 2312 + 201 + 000000000 = 41231212345678912312201000000000
2. Split the result Key of step 1 into 2 blocks
Block 1 = 4123121234567891
Block 2 = 2312201000000000
3. Take the 16-Byte (32 Hexadecimal) CVV Key and split into 2 Blocks
CVV Key = 1234567890ABCDEF5678901234ABCDEF
Block 1 = 1234567890ABCDEF
Block 2 = 5678901234ABCDEF
4. Encrypt Block 1 of Step 02 by using the Block 1 of Step 3 (DES algorithm)
Encrypt 4123121234567891 by 1234567890ABCDEF
Result = 453E04E1ACAAE2BB
5. Perform XOR on the result of Step 4 with Block 2 of Step 2
453E04E1ACAAE2BB XOR 2312201000000000
Result = 662C24F1ACAAE2BB
6. Encrypt the result of Step 5 by Block 1 of Step 3 (DES algorithm)
Encrypt 662C24F1ACAAE2BB by 1234567890ABCDEF
Result = E188C879876B95C3
7. Decrypt the result of Step 6 by Block 2 of Step 3 (DES algorithm)
Decrypt E188C879876B95C3 by 5678901234ABCDEF
Result = 1D64BCD5CD791E95
8. Encrypt the result of Step 07 by Block 1 of Step 3 (DES algorithm)
Encrypt 1D64BCD5CD791E95 by 1234567890ABCDEF
Result = 96C0C9362DE4768A
9. Extract all numeric digits from the result of Step 8
Result = 96093624768
10. Get the first 3 numeric of the result of Step 9 and it the calculated CVV/CVN
Result = 960 is the calculated CVV/CVN
EXAMPLE
So taking as parameters
partial_pan = '4987650006321328
expiry_date = '1226'
#!/usr/bin/python3
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import re
def pad_key(key):
return key + b'0' * (32 - len(key))
def split_blocks(key):
return key[:16], key[16:]
def aes_encrypt(block, key):
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
encryptor = cipher.encryptor()
return encryptor.update(block) + encryptor.finalize()
def aes_decrypt(block, key):
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
decryptor = cipher.decryptor()
return decryptor.update(block) + decryptor.finalize()
def perform_xor(block1, block2):
return bytes([b1 ^ b2 for b1, b2 in zip(block1, block2)])
def extract_numeric_digits(data):
return ''.join(filter(str.isdigit, data.decode()))
def calculate_cvv_part1(partial_pan, expiry_date, verbose=False):
key = pad_key(partial_pan.encode() + expiry_date.encode() + b'00000')
block1, block2 = split_blocks(key)
cvv_key = b'1234567890ABCDEF5678901234ABCDEF'
cvv_block1, cvv_block2 = split_blocks(cvv_key)
if verbose:
print("Step 1: Padding the key")
print("Padded Key:", key)
encrypted_block1 = aes_encrypt(block1, cvv_block1)
if verbose:
print("\nStep 2: Encrypting Block 1 of Step 1 using Block 1 of CVV Key")
print("Encrypted Block 1:", encrypted_block1.hex().upper())
xor_result = perform_xor(encrypted_block1, block2)
if verbose:
print("\nStep 3: Performing XOR operation with Block 2 of Step 1")
print("XOR Result:", xor_result.hex().upper())
encrypted_xor_result = aes_encrypt(xor_result, cvv_block1)
if verbose:
print("\nStep 4: Encrypting XOR Result using Block 1 of CVV Key")
print("Encrypted XOR Result:", encrypted_xor_result.hex().upper())
return encrypted_xor_result, cvv_block2
def calculate_cvv_part2(encrypted_xor_result, cvv_block2, verbose=False):
decrypted_result = aes_decrypt(encrypted_xor_result, cvv_block2)
if verbose:
print("\nStep 5: Decrypting Result using Block 2 of CVV Key")
print("Decrypted Result:", decrypted_result.hex().upper())
encrypted_final_result = aes_encrypt(decrypted_result, cvv_block1)
if verbose:
print("\nStep 6: Encrypting Decrypted Result using Block 1 of CVV Key")
print("Final Encrypted Result:", encrypted_final_result.hex().upper())
numeric_cvv = extract_numeric_digits(encrypted_final_result)
if verbose:
print("\nStep 7: Extracting numeric digits")
print("Numeric CVV:", numeric_cvv)
cvv = numeric_cvv[:3]
if verbose:
print("\nStep 8: Taking the first 3 digits as calculated CVV/CVN")
print("Calculated CVV/CVN:", cvv)
return cvv
# Example usage with verbosity
partial_pan = '4987650006321328'
expiry_date = '1226'
encrypted_xor_result, cvv_block2 = calculate_cvv_part1(partial_pan, expiry_date, verbose=True)
calculated_cvv = calculate_cvv_part2(encrypted_xor_result, cvv_block2, verbose=True)
print("\nFinal calculated CVV/CVN:", calculated_cvv)
and here full debug of process:
Step 1: Padding the key
Padded Key: b'49876500063213280000000000000000'
Step 2: Encrypting Block 1 of Step 1 using Block 1 of CVV Key
Encrypted Block 1: B46F62B1D4DE819C25D92ABBA8E7D3DD
Step 3: Performing XOR operation with Block 2 of Step 1
XOR Result: 8B11D43A6E7A811C8D88280C52C3D3DD
Step 4: Encrypting XOR Result using Block 1 of CVV Key
Encrypted XOR Result: 067B8284C928E729153C10466AFBC29D
Step 5: Decrypting Result using Block 2 of CVV Key
Decrypted Result: ABD0BBDE565F1B1094DC10362D703A6B
Step 6: Encrypting Decrypted Result using Block 1 of CVV Key
Final Encrypted Result: 9A0F349A62B08ED9DA15A87978AB7E94
Step 7: Extracting numeric digits
Numeric CVV: 934962089479894
Step 8: Taking the first 3 digits as calculated CVV/CVN
Calculated CVV/CVN: 934
Final calculated CVV/CVN: 934
Problem is CVV is not correct, should be 904, runned it severl times with different numbers always one digit in the middle is wrong! Any help appreciated
Calculating the CVV1, CVV2, iCVV
1. Concatenate the PAN, expiry date and service code and pad right with zeros to get 16-bytes (32 Hexadecimal string) key value
4123121234567891 + 2312 + 201 + 000000000 = 41231212345678912312201000000000
2. Split the result Key of step 1 into 2 blocks
Block 1 = 4123121234567891
Block 2 = 2312201000000000
3. Take the 16-Byte (32 Hexadecimal) CVV Key and split into 2 Blocks
CVV Key = 1234567890ABCDEF5678901234ABCDEF
Block 1 = 1234567890ABCDEF
Block 2 = 5678901234ABCDEF
4. Encrypt Block 1 of Step 02 by using the Block 1 of Step 3 (DES algorithm)
Encrypt 4123121234567891 by 1234567890ABCDEF
Result = 453E04E1ACAAE2BB
5. Perform XOR on the result of Step 4 with Block 2 of Step 2
453E04E1ACAAE2BB XOR 2312201000000000
Result = 662C24F1ACAAE2BB
6. Encrypt the result of Step 5 by Block 1 of Step 3 (DES algorithm)
Encrypt 662C24F1ACAAE2BB by 1234567890ABCDEF
Result = E188C879876B95C3
7. Decrypt the result of Step 6 by Block 2 of Step 3 (DES algorithm)
Decrypt E188C879876B95C3 by 5678901234ABCDEF
Result = 1D64BCD5CD791E95
8. Encrypt the result of Step 07 by Block 1 of Step 3 (DES algorithm)
Encrypt 1D64BCD5CD791E95 by 1234567890ABCDEF
Result = 96C0C9362DE4768A
9. Extract all numeric digits from the result of Step 8
Result = 96093624768
10. Get the first 3 numeric of the result of Step 9 and it the calculated CVV/CVN
Result = 960 is the calculated CVV/CVN
EXAMPLE
So taking as parameters
partial_pan = '4987650006321328
expiry_date = '1226'
#!/usr/bin/python3
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import re
def pad_key(key):
return key + b'0' * (32 - len(key))
def split_blocks(key):
return key[:16], key[16:]
def aes_encrypt(block, key):
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
encryptor = cipher.encryptor()
return encryptor.update(block) + encryptor.finalize()
def aes_decrypt(block, key):
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
decryptor = cipher.decryptor()
return decryptor.update(block) + decryptor.finalize()
def perform_xor(block1, block2):
return bytes([b1 ^ b2 for b1, b2 in zip(block1, block2)])
def extract_numeric_digits(data):
return ''.join(filter(str.isdigit, data.decode()))
def calculate_cvv_part1(partial_pan, expiry_date, verbose=False):
key = pad_key(partial_pan.encode() + expiry_date.encode() + b'00000')
block1, block2 = split_blocks(key)
cvv_key = b'1234567890ABCDEF5678901234ABCDEF'
cvv_block1, cvv_block2 = split_blocks(cvv_key)
if verbose:
print("Step 1: Padding the key")
print("Padded Key:", key)
encrypted_block1 = aes_encrypt(block1, cvv_block1)
if verbose:
print("\nStep 2: Encrypting Block 1 of Step 1 using Block 1 of CVV Key")
print("Encrypted Block 1:", encrypted_block1.hex().upper())
xor_result = perform_xor(encrypted_block1, block2)
if verbose:
print("\nStep 3: Performing XOR operation with Block 2 of Step 1")
print("XOR Result:", xor_result.hex().upper())
encrypted_xor_result = aes_encrypt(xor_result, cvv_block1)
if verbose:
print("\nStep 4: Encrypting XOR Result using Block 1 of CVV Key")
print("Encrypted XOR Result:", encrypted_xor_result.hex().upper())
return encrypted_xor_result, cvv_block2
def calculate_cvv_part2(encrypted_xor_result, cvv_block2, verbose=False):
decrypted_result = aes_decrypt(encrypted_xor_result, cvv_block2)
if verbose:
print("\nStep 5: Decrypting Result using Block 2 of CVV Key")
print("Decrypted Result:", decrypted_result.hex().upper())
encrypted_final_result = aes_encrypt(decrypted_result, cvv_block1)
if verbose:
print("\nStep 6: Encrypting Decrypted Result using Block 1 of CVV Key")
print("Final Encrypted Result:", encrypted_final_result.hex().upper())
numeric_cvv = extract_numeric_digits(encrypted_final_result)
if verbose:
print("\nStep 7: Extracting numeric digits")
print("Numeric CVV:", numeric_cvv)
cvv = numeric_cvv[:3]
if verbose:
print("\nStep 8: Taking the first 3 digits as calculated CVV/CVN")
print("Calculated CVV/CVN:", cvv)
return cvv
# Example usage with verbosity
partial_pan = '4987650006321328'
expiry_date = '1226'
encrypted_xor_result, cvv_block2 = calculate_cvv_part1(partial_pan, expiry_date, verbose=True)
calculated_cvv = calculate_cvv_part2(encrypted_xor_result, cvv_block2, verbose=True)
print("\nFinal calculated CVV/CVN:", calculated_cvv)
and here full debug of process:
Step 1: Padding the key
Padded Key: b'49876500063213280000000000000000'
Step 2: Encrypting Block 1 of Step 1 using Block 1 of CVV Key
Encrypted Block 1: B46F62B1D4DE819C25D92ABBA8E7D3DD
Step 3: Performing XOR operation with Block 2 of Step 1
XOR Result: 8B11D43A6E7A811C8D88280C52C3D3DD
Step 4: Encrypting XOR Result using Block 1 of CVV Key
Encrypted XOR Result: 067B8284C928E729153C10466AFBC29D
Step 5: Decrypting Result using Block 2 of CVV Key
Decrypted Result: ABD0BBDE565F1B1094DC10362D703A6B
Step 6: Encrypting Decrypted Result using Block 1 of CVV Key
Final Encrypted Result: 9A0F349A62B08ED9DA15A87978AB7E94
Step 7: Extracting numeric digits
Numeric CVV: 934962089479894
Step 8: Taking the first 3 digits as calculated CVV/CVN
Calculated CVV/CVN: 934
Final calculated CVV/CVN: 934
Problem is CVV is not correct, should be 904, runned it severl times with different numbers always one digit in the middle is wrong! Any help appreciated