in scram/aes_scram.py [0:0]
def scram_decrypt(K, N, A, C, X, Tag):
"""
SCRAM Decryption
Parameters:
K: Key
N: Nonce
A: Additional Authenticated Data
C: Ciphertext
X: Encrypted Random value R and Padding Length
Tag: Tag
Returns:
M_calculated: The decrypted Message
"""
# Derive MAC key (KM)
# S2 = N || 0x00 0x00 0x00 0x2 || 0^{8} || 0^{8} || 0^{16} || 0^{32}
S2_calculated = N + byteStr(0x02, 4) + byteStr(0x0, 8) + byteStr(0x0, 8) + byteStr(0x0, 16) + byteStr(0x0, 32)
U2_calculated = hmac.new(K, S2_calculated, hashlib.sha512).digest()
KM_calculated = U2_calculated[0:32]
# Derive T
# T = GMAC (N, A||C, null)
T_calculated = AES.new(key=KM_calculated, mode=AES.MODE_GCM, nonce=N).update(A + C).digest()
# Derive one-time pad U3 from T_calculated,
# S3 = N || 0x00 0x00 0x00 0x3 || 0^{8} || 0^{8} || T || 0^{32}
S3_calculated = N + byteStr(0x03, 4) + byteStr(0x0, 8) + byteStr(0x0, 8) + T_calculated + byteStr(0x0, 32)
U3_calculated = hmac.new(K, S3_calculated, hashlib.sha512).digest()
# Decrypt R and PADDING_LEN, by xor'ing X and U3
R_calculated = bytes(a ^ b for (a, b) in zip(U3_calculated[0:32], X[0:32]))
PADDING_LEN_STR_calculated = bytes(a ^ b for (a, b) in zip(U3_calculated[32:34], X[32:34]))
# Derive Message and Padding Lengths
PADDING_LEN_calculated = int.from_bytes(PADDING_LEN_STR_calculated, ENDIANNESS)
M_LEN_calculated = len(C) - PADDING_LEN_calculated
# Authenticate R
# S4 = N || 0x00 0x00 0x00 0x4 || A_LEN_STR || M_LEN_STR || T || R
S4_calculated = N + byteStr(0x04, 4) + byteStr(len(A), 8) + \
byteStr(M_LEN_calculated, 8) + T_calculated + R_calculated
U4_calculated = hmac.new(K, S4_calculated, hashlib.sha512).digest()
Tag_calculated = U4_calculated[0:16]
if (Tag == Tag_calculated):
print("PASSED: Authentication")
else:
print("FAILED: Authentication")
return None
# Now that Ciphertext and other parameters are authenticated, we can decrypt Ciphertext to get Plaintext
# Derive Message Encryption key (KE)
# S1 = N || 0x00 0x00 0x00 0x1 || 0^{8} || 0^{8} || 0^{16} || R
S1_calculated = N + byteStr(0x01, 4) + byteStr(0x0, 8) + byteStr(0x0, 8) + byteStr(0x0, 16) + R_calculated
U1_calculated = hmac.new(K, S1_calculated, hashlib.sha512).digest()
KE_calculated = U1_calculated[0:32]
# Decrypt Ciphertext
PADDED_MSG_calculated = AES.new(key=KE_calculated, mode=AES.MODE_CTR, nonce=N).decrypt(C)
# Strip off padding bytes
M_calculated = PADDED_MSG_calculated[0:M_LEN_calculated]
if DEBUG_ENABLED:
print("\nDecryption Debug Info: ")
debugByteStr("S1_calculated", S1_calculated)
debugByteStr("S2_calculated", S2_calculated)
debugByteStr("S3_calculated", S3_calculated)
debugByteStr("S4_calculated", S4_calculated)
debugByteStr("U1_calculated", U1_calculated)
debugByteStr("U2_calculated", U2_calculated)
debugByteStr("U3_calculated", U3_calculated)
debugByteStr("U4_calculated", U4_calculated)
debugByteStr("T_calculated", T_calculated)
debugByteStr("R_calculated", R_calculated)
debugByteStr("KE_calculated", KE_calculated)
debugByteStr("KM_calculated", KM_calculated)
debugByteStr("PADDED_MSG_calculated", PADDED_MSG_calculated)
debugByteStr("M_calculated", M_calculated)
return M_calculated