diff --git a/core/pit/README.md b/core/pit/README.md new file mode 100644 index 00000000..32ffb397 --- /dev/null +++ b/core/pit/README.md @@ -0,0 +1,21 @@ + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ +PIT-Cerberus Framework + +## This readme will contain information about the protection in transit features added. + +pit_crypto.h/.c: Contains all the encryption, decrtption, keygeneration, OTP Generation and Validation functions. +pit.h/.c: Contains locking and unlocking functions. +pit_client.h/.c: Contains C-socket to connect with server. +pit-server.py: A server to communicate. + +How to run with the server: + +1. Run the server first, it will wait for client to connect. +2. Build the Project-Cerberus as define in main readme. \ No newline at end of file diff --git a/core/pit/pit-server.py b/core/pit/pit-server.py new file mode 100644 index 00000000..78b24ca3 --- /dev/null +++ b/core/pit/pit-server.py @@ -0,0 +1,179 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT license. +# +# Developed by AMI Inc. & Colorado State University. +# Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com + +from cryptography.hazmat.primitives.serialization import load_der_public_key +from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey +from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1 +from cryptography.hazmat.primitives.asymmetric.ec import ECDH +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.serialization import KeySerializationEncryption +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.ciphers.aead import AESGCM +import os + +import socket + +HOST = "127.0.0.1" # Standard loopback interface address (localhost) +PORT = 5572 # Port to listen on (non-privileged ports are > 1023) +SHARED_SECRET_LEN = 32 +DER_LEN = 91 #length of der encoding for this message +MSG_SIZE = 128 +IV_SIZE = 12 +TAG_SIZE = 16 +server_private_key = ec.generate_private_key(ec.SECP256R1) +server_public_key = server_private_key.public_key() +print(f"Generated: Server ECC Key Pair.") +print() +print(f"Server X value : {server_public_key.public_numbers().x}\nServer y value : {server_public_key.public_numbers().y}") +server_public_der = server_public_key.public_bytes(encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo) +server_private_der = server_private_key.private_bytes(encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()) + +server_public_pem = server_public_key.public_bytes(encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) +server_private_pem = server_private_key.private_bytes(encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()) +# print(server_public_der) + +#Ex secret key - 2\t\xdb\x8a\xb4%D\xb3\x07\x1f\xdb\x00$\x02\xbe\xeco\xad\xbd\xc7\x8c\xe7\xad\x14\xedVLh\xecZ\x89\xcf +#server_public_der = b'0Y0\x13\x06\x07*\x86H\xce=\x02\x01\x06\x08*\x86H\xce=\x03\x01\x07\x03B\x00\x04\xe4Mn\xcc\x83O\xc0Fm&\x9b\xb2\x7f\xb3\xdf\xb6E\xcd\xcd\x8b\x15\x02\xb3[\xac5\xc9V\xa8\x9db1\x07\xb9\xf6\x89\xc5\x9f\xb6e\x1f\x8f\x10e\xf1\x99\x0c\xb83g\x89%\x80\x1d\x1as\xef\xe2q\x91\xaf\xd1\'\xeb' + +raw_client_pub_key = None; + +# with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind((HOST, PORT)) +s.listen() +print("listening") +conn, addr = s.accept() +print("accepted") + +print(f"Connected by {addr}") + +#Set up vars +client_public_key = None; +# data = conn.recv(5) +# print(data) +# if(data[:4] == b"lock"): +data = conn.recv(DER_LEN) +raw_client_pub_key = data +client_public_key = load_der_public_key(data) +print(f"Recived: Cerberus ECC Key Pair.") +print() +print(f"Client X value : {client_public_key.public_numbers().x}\nClient y value : {client_public_key.public_numbers().y}") + +conn.sendall(server_public_der) +conn.close() +s.close() + +##Start of changes +print() +print("Generating shared secret..... Successful.") +shared_secret = server_private_key.exchange(ec.ECDH(), client_public_key) + +# #Encrypt a product ID, send it over +s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s2.bind((HOST, 5574)) +s2.listen() +print("listening") +conn_pid, addr_pid = s2.accept() + +iv = conn_pid.recv(IV_SIZE) + +PID = b"ABCDEFGHIJKLMNOP" +aes_pid = AESGCM(shared_secret) +ePID = aes_pid.encrypt(iv, PID, None) +pid_tag = ePID[-16:] +ePID = ePID[:-16] + +conn_pid.sendall(ePID) +conn_pid.sendall(pid_tag) +s2.close() + +##End of changes + + +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind((HOST, 5573)) +s.listen() +print("listening") +conn, addr = s.accept() +print("accepted") +print(f"Connected by {addr}") +client_otp = conn.recv(MSG_SIZE) +print(f"[DEMO]: Encrypted OTP : {client_otp}\n") +iv = conn.recv(IV_SIZE) +client_tag = conn.recv(TAG_SIZE) + + + + + + +aesgcm = AESGCM(shared_secret) +#16 byte tag gets appended to the encrypted data +decrypted_client_message = aesgcm.decrypt(iv, client_otp + client_tag, None) + +# print(f"Is decrypted client msg same as the original otp? (should be true) {client_og_otp == decrypted_client_message}") +with open("OTP", "wb") as f: + f.write(decrypted_client_message) +#print("[DEMO(1)]: Decrypting OTP to showcase it is the same on the client and server. Original OTP is") +#os.system("cat OTP") +#print() + + + + +difference = 128 - len(client_otp) +full_message = client_otp + (b'\0' * difference) +aes_send = AESGCM(shared_secret) +ct = aes_send.encrypt(iv, full_message, None) +serv_tag = ct[-16:] +serv_encrypted_data = ct[:-16] +serv_decrypted_data_with_tag = aes_send.decrypt(iv, serv_encrypted_data + serv_tag, None) +serv_decrypted_data = serv_decrypted_data_with_tag[:-16] + +#print(f"[DEMO(2)]: Performing an AES encryption of OTPs (will be used between user and server in reality)...") +#print(f"[DEMO(2)]: Server's encrypted OTPs is : {serv_encrypted_data}\n") + +#print(f"[DEMO(3)]: Performing decryption on previously encrypted OTPs (will be used between user and server in reality)...") +#print(f"[DEMO(3)]: Server's decrypted OTPs (should be original OTPs) is : {serv_decrypted_data_with_tag}\n") + +#print(f"[DEMO(3)]: Was the server able to encrypt OTPs and decrypt it successfully? {serv_decrypted_data_with_tag == client_otp}\n") + + +#print(f"[DEMO(4)]: Server (will be user in reality) sending OTPs back to client for validation...") + + + +import os +import math +import random +import smtplib +OTP = client_otp + +#otp = OTP + " is your OTP" +msg = OTP +msg = str(msg) +s = smtplib.SMTP('smtp.gmail.com', 587) +s.starttls() + +s.login("rakrock121212@gmail.com", "iobcalxelblakshq") +# emailid = input("Enter your email: ") +# print(emailid) +s.sendmail('rakrock121212@gmail.com', emailid, msg) +# a = input("Enter Your OTP >>: ") +# if a == OTP: +# print("Verified") +# else: +# print("Please Check your OTP again") + + + +#user_input = input() +#user_input = bytes(user_input, 'utf-8') + +#conn.sendall(user_input) +conn.sendall(client_tag) +s.close() diff --git a/core/pit/pit.c b/core/pit/pit.c new file mode 100644 index 00000000..f37eefb1 --- /dev/null +++ b/core/pit/pit.c @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ + +#include +#include +#include +#include +#include +#include "crypto/ecc.h" +#include "crypto/ecc_mbedtls.h" +#include "crypto/aes_mbedtls.h" +#include "mbedtls/ecp.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/error.h" +#include "crypto/rng_mbedtls.h" +#include "pit_crypto.h" +#include +#include "pit.h" +#include +#include "pit_client.h" + + +uint8_t *shared_secret; // Global variable to store secret key; +int shared_length; // Secret Key Length; +struct ecc_private_key priv_key; // ECC Private Key; +struct ecc_public_key pub_key; // ECC Public Key; +uint8_t class_OTPs [128]; // OTP Varibale; +int state; // State of PIT Protocol; + +/** + * Sets up needed variables and sets the systems state to lock. + * Exchanges keys with the server to create a secret key + * @param secret A 32-byte empty array which will be loaded with the shared secret + * @return 1 on success +*/ +int pit_Lock(uint8_t *secret){ + + size_t keysize = (256 / 8); + + int key_stat = pit_keygenstate(keysize, &priv_key, &pub_key, &state); + if(key_stat != 1){ + return PIT_KEY_GEN_FAILURE; + } + + struct ecc_engine_mbedtls engine; + ecc_mbedtls_init (&engine); + struct ecc_public_key pub_key_serv; + shared_length = engine.base.get_shared_secret_max_length(&engine.base, &priv_key); + shared_secret = malloc( 8 * shared_length); + + uint8_t *pub_der = NULL; + size_t der_length; + engine.base.get_public_key_der (&engine.base, &pub_key, &pub_der, &der_length); + + uint8_t buffer[der_length]; + bzero(buffer, der_length); + + keyexchangestate(pub_der, der_length, buffer); + + engine.base.init_public_key(&engine.base, buffer, der_length, &pub_key_serv); + ecc_mbedtls_release (&engine); + key_stat = pit_secretkey(&priv_key, &pub_key_serv, secret, &state); + + if(key_stat != 1){ + return PIT_SECRET_KEY_GEN_FAILURE; + } + + memcpy(shared_secret, secret, shared_length); + state = 0; + return SUCCESS; +} + +/** + * Unlocks the state of the machine by validating OTP + * Creates an OTP, then encrypts it as OTPs. Sends OTPs to the server. + * Server then encrypts OTPs again, then sends it back to the client. + * Client decrypts server's message and validates OTPs against original OTP + * @return 1 on success +*/ + +int pit_Unlock(){ + int my_state; + uint8_t unlock_aes_iv[] = { + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b + }; + + int product_id_size = 16; + uint8_t ePID[16]; + uint8_t ePID_tag[16]; + bool isValidPID = false; + printf("User initiated Unlock Request......\n"); + + receive_product_info(ePID, ePID_tag, product_id_size, unlock_aes_iv, sizeof(unlock_aes_iv)); + + int pid_status = pit_OTPvalidation(shared_secret, shared_length, unlock_aes_iv, sizeof(unlock_aes_iv), ePID_tag, ePID, sizeof(ePID), (unsigned char *)PRODUCT_ID, &isValidPID, &my_state); + if(pid_status==1) + printf("PRODUCT ID Validation Successful. pid_status is: %d\n", pid_status ); + else + printf("PRODUCT ID Validation Fails. pid_status is: %d\n", pid_status ); + + int otp_size = 128; + uint8_t OTP_tag[16]; + uint8_t OTP[otp_size]; + uint8_t OTPs[otp_size]; + + int status = pit_OTPgen(shared_secret, shared_length, unlock_aes_iv, sizeof(unlock_aes_iv), OTP_tag, OTP, otp_size, OTPs, &my_state); + memcpy(class_OTPs, OTPs, otp_size); + if(status != 1){ + return PIT_OTP_GENERATION_FAILURE; + } + printf("OTP Generation and Encryption Successful.\n"); + + uint8_t serv_enc[128]; + uint8_t server_encrypted_message[128]; + uint8_t server_tag[16]; + //Send OTPs to server + send_unlock_info(OTPs, sizeof(OTPs), unlock_aes_iv, sizeof(unlock_aes_iv), OTP_tag, serv_enc, server_tag); + printf("Encrypted OTP sent to Server.\n"); + + bool isValid = false; + printf("Please Enter your OTP:\n"); + unsigned int temp_server_encrypted_message; + scanf("%u", &temp_server_encrypted_message); + if (temp_server_encrypted_message > UINT8_MAX) { + printf("Value out of range for uint8_t.\n"); + return 1; + } + *server_encrypted_message = (uint8_t)temp_server_encrypted_message; + + pit_OTPvalidation(shared_secret, shared_length, unlock_aes_iv, sizeof(unlock_aes_iv), server_tag, server_encrypted_message, sizeof(server_encrypted_message), OTP, &isValid, &my_state); + if(pid_status==1) + printf("OTP Validation Successful. pid_status is: %d\n", pid_status ); + else + printf("OTP Validation Fails. pid_status is: %d\n", pid_status ); + exit(20); //TODO : Remove + if(isValid){ + state = 7; + return SUCCESS; + } + return PIT_UNLOCK_NOT_VALID; + +} + +/** Gets the state of the system + * @return The numerical value of the state of the system at the moment of calling +*/ +int get_state(){ + return state; +} + +/** + * Get the encrypted OTP (OTPs) from the system + * @param OTPs Empty buffer to hold the encrypted OTP into + * @return 1 on success +*/ +int get_OTPs(uint8_t *OTPs){ + memcpy(OTPs, class_OTPs, 128); //Size of OTPs is always 128 + return 1; +} + + + diff --git a/core/pit/pit.h b/core/pit/pit.h new file mode 100644 index 00000000..3a6c71e0 --- /dev/null +++ b/core/pit/pit.h @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ + +#include +#include +#include +#include +#include +#include + + +#define PRODUCT_ID "ABCDEFGHIJKLMNOP" +#define SUCCESS 1 + +int pit_Lock(uint8_t *secret); + +int pit_Unlock(); + +int get_state(); + +int get_OTPs(uint8_t *OTPs); + +#define PIT_ERROR(code) ROT_ERROR (ROT_MODULE_PIT, code) + +/** + * Error codes that can be generated by a hash or HMAC engine. + */ +enum { + PIT_KEY_GEN_FAILURE = PIT_ERROR (0x00), /** Failure when generating a key-pair*/ + PIT_SECRET_KEY_GEN_FAILURE = PIT_ERROR (0x01), /** Failure when generating secret-key*/ + PIT_OTP_GENERATION_FAILURE = PIT_ERROR(0x02), /** Failure when generating OTP*/ + PIT_UNLOCK_NOT_VALID = PIT_ERROR(0x03), +}; \ No newline at end of file diff --git a/core/pit/pit_client.c b/core/pit/pit_client.c new file mode 100644 index 00000000..23646c6d --- /dev/null +++ b/core/pit/pit_client.c @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ + +#include +#include "pit_client.h" +#include "crypto/ecc_mbedtls.h" +#include "mbedtls/ecdh.h" +#include +#include +#include + +/** +* Initiate a connection to desired server. Dependent on implementation (Socket vs i2c) +* @param desired_port The desired port to connect to the server on (Need not implement if using i2c) +* @return A file descriptor pointing to the socket (server implementation) +*/ + +int pit_connect(int desired_port){ + // Communicate w/ server, (will be i2c in final version, must be overwritten) (expand on this) + char* ip = "127.0.0.1"; + int port = desired_port; + + int sock; + struct sockaddr_in addr; + + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0){ + + return PIT_I2C_CONNECTION_FAILURE; + + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = inet_addr(ip); + + if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) != 0) { + + return PIT_I2C_CONNECTION_FAILURE; + } + return sock; +} + +/** + * On success, keyexchangestate should initialize pubkey_serv with the server's public key + * @param pubkey_cli The initialized public key for the client (Machine using cerberus) + * @param pubkey_serv An uninitialized public key to store the server's public key into + * @return 1 on success +*/ + //May need to override depending on how pit_connect is implemented +int keyexchangestate(uint8_t *pubkey_cli, size_t pubkey_der_length, uint8_t *pubkey_serv){ + int sock = pit_connect(5572); + + send(sock, pubkey_cli, pubkey_der_length, 0); //Will always be length 91 for this curve, send client public key (DER Format) + + recv(sock, pubkey_serv, pubkey_der_length, 0); //Receive the server's public key (DER Format) + + return SUCCESS; +} + +/** + * Sends OTPs, AES IV, and the AES-GCM Tag for OTP encryption to the server, receives the server's encrypted message and tag for that message back + * @param OTPs The Encrypted OTP to send + * @param OTPs_size Size (in bytes) of the OTPs + * @param unlock_aes_iv The AES IV used to encrypt the OTP into OTPs + * @param unlock_aes_iv_size Size (in bytes) of the unlock_aes_iv param + * @param OTP_tag The AES-GCM Tag generated when encrypting OTP into OTPs + * @param server_encrypted_message An empty buffer to hold the server's response message (which will then be validated in the unlock API) + * @param server_tag The AES-GCM tag for the server's encrypted message + * @return 1 on success +*/ + +int send_unlock_info(uint8_t *OTPs, size_t OTPs_size, uint8_t *unlock_aes_iv, size_t unlock_aes_iv_size, uint8_t *OTP_tag, uint8_t *server_encrypted_message, uint8_t *server_tag){ + int sock = pit_connect(5573); + send(sock, OTPs, OTPs_size, 0); //Send OTPs + send(sock, unlock_aes_iv, unlock_aes_iv_size, 0); //Send the IV for the AES cipher + send(sock, OTP_tag, 16, 0); //Send AES-GCM tag + + // printf("Please Enter your OTP:\n"); + // scanf("%d", &server_encrypted_message); + recv(sock, server_tag, 16, 0); //Receive server's message tag + + return SUCCESS; +} + + +int receive_product_info(uint8_t *EncryptedProductID, uint8_t *EncryptedProductIDTag, size_t ProductIDSize, uint8_t *aes_iv, size_t aes_iv_size){ + //printf("Trying to connect in receive_product_info...\n"); + int sock = pit_connect(5574); + send(sock, aes_iv, aes_iv_size, 0); + recv(sock, EncryptedProductID, ProductIDSize, 0); + recv(sock, EncryptedProductIDTag, 16, 0); + return SUCCESS; + +} \ No newline at end of file diff --git a/core/pit/pit_client.h b/core/pit/pit_client.h new file mode 100644 index 00000000..3749563e --- /dev/null +++ b/core/pit/pit_client.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ + +#include "mbedtls/ecdh.h" +#include "crypto/ecc_mbedtls.h" +#define SUCCESS 1 + +int pit_connect(int desired_port); + +int keyexchangestate(uint8_t *pubkey_cli, size_t pubkey_der_length, uint8_t *pubkey_serv); + +int send_unlock_info(uint8_t *OTPs, size_t OTPs_size, uint8_t *unlock_aes_iv, size_t unlock_aes_iv_size, uint8_t *OTP_tag, uint8_t *server_encrypted_message, uint8_t *server_tag); + + + +int receive_product_info(uint8_t *EncryptedProductID, uint8_t *EncryptedProductIDTag, size_t ProductIDSize, uint8_t *aes_iv, size_t aes_iv_size); + +#define PIT_I2C_ERROR(code) ROT_ERROR (ROT_MODULE_PIT_CRYPTO, code) + +/** + * Error codes that can be generated by a hash or HMAC engine. + */ +enum { + PIT_I2C_CONNECTION_FAILURE = PIT_I2C_ERROR (0x00), /** Decryption failed*/ +}; + diff --git a/core/pit/pit_crypto.c b/core/pit/pit_crypto.c new file mode 100644 index 00000000..9e58b9b8 --- /dev/null +++ b/core/pit/pit_crypto.c @@ -0,0 +1,215 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ + +#include +#include +#include +#include +#include +#include "crypto/ecc.h" +#include "crypto/ecc_mbedtls.h" +#include "crypto/aes_mbedtls.h" +#include "mbedtls/pk.h" +#include "testing/crypto/ecc_testing.h" +#include "mbedtls/ecp.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/ecdh.h" +#include "mbedtls/error.h" +#include "crypto/rng_mbedtls.h" +#include +#include "pit.h" +#include +#include "pit_client.h" +#include "pit_crypto.h" + + +/** + * Generates a key pair, sets the state appropriately + * @param key_length The length of key to use in bytes. 256, 381, 521 bits (so X / 8 bytes) are the supported lengths + * @param privkey Output for the initialized private key + * @param pubkey Output for the initialized public key + * @param state An int to hold the numerical value of the state + * @return 1 on success +*/ + +int pit_keygenstate(size_t key_length, struct ecc_private_key *privkey, struct ecc_public_key *pubkey, int *state){ + struct ecc_engine_mbedtls engine; + ecc_mbedtls_init (&engine); + int status = engine.base.generate_key_pair(&engine.base, key_length, privkey, pubkey); + + *state = 1; + ecc_mbedtls_release (&engine); + if(status == 0){ + return SUCESS; + } + else{ + return PIT_CRYPTO_KEY_GENERATION_FAILED; + } + +} + +/** + * Generates a secret key - AES Shared Key + * @param privkey The private key used to generate the secret + * @param pubkey The public key used to generate the secret + * @param secret An non-null output buffer to hold the generated shared secret + * @param state An int to hold the numerical value of the state + * @return 1 on success +*/ + +int pit_secretkey(struct ecc_private_key *privkey, struct ecc_public_key *pubkey, uint8_t *secret, int *state){ + struct ecc_engine_mbedtls engine; + ecc_mbedtls_init (&engine); + int shared_length = engine.base.get_shared_secret_max_length(&engine.base, privkey); + uint8_t out[shared_length]; + int status = engine.base.compute_shared_secret(&engine.base, privkey, pubkey, out, sizeof (out)); + ecc_mbedtls_release (&engine); + + memcpy(secret, out, shared_length); + + if(shared_length != status){ + return PIT_CRYPTO_SECRET_KEY_NOT_EXPECTED_LENGTH; + } + *state = 3; + return SUCESS; +} + +/** + * Uses AES-GCM encryption to encrypt a message into ciphertext using a secret key + * @param msg A plaintext message you would like to encrypt + * @param msg_size The size of the plaintext message + * @param secret A secret key to use for encryption + * @param secret_length The size of the secret key + * @param AESIV An IV to use for encryption. A 12-byte IV is best (meets NIST standards) + * @param AESIV_SIZE The size of the IV used for encryption + * @param tag The buffer to hold the GCM authentication tag. All tags will be 16 bytes + * @param ciphertext An empty output buffer to hold the encrypted data. The ciphertext will be the same length as the plaintext + * @param state An int to hold the numerical value of the state + * @return 1 on success +*/ +int pit_encryption(uint8_t *msg, size_t msg_size, uint8_t *secret, size_t secret_length, uint8_t *AESIV, size_t AESIV_SIZE, uint8_t *tag, uint8_t *ciphertext, int *state){ + struct aes_engine_mbedtls aes_engine; + aes_mbedtls_init (&aes_engine); + + aes_engine.base.set_key(&aes_engine.base, secret, secret_length); + int status = aes_engine.base.encrypt_data (&aes_engine.base, msg, msg_size, AESIV, + AESIV_SIZE, ciphertext, msg_size, tag, 16); + aes_mbedtls_release(&aes_engine); + + *state = 4; + if(status != 0){ + return PIT_CRYPTO_ENCRYPTION_FAILED; + } + return SUCESS; + +} + +/** + * Uses AES-GCM encryption to decrypt a message from ciphertext using a secret key + * @param ciphertext The ciphertext you would like to decrypt + * @param ciphertext_size The size of the ciphertext message + * @param secret A secret key to use for encryption + * @param secret_length The size of the secret key + * @param AESIV An IV to use for encryption. A 12-byte IV is best (meets NIST standards) + * @param AESIV_SIZE The size of the IV used for encryption + * @param tag The buffer to hold the GCM authentication tag. All tags will be 16 bytes + * @param plaintext The buffer to hold the decrypted ciphertext (Will be the same size as the ciphertext) + * @return 1 on success +*/ + +int pit_decryption(uint8_t *ciphertext, size_t ciphertext_size, uint8_t *secret, size_t secret_length, uint8_t *AESIV, size_t AESIV_SIZE, uint8_t *tag, uint8_t *plaintext, int *state){ + struct aes_engine_mbedtls aes_engine; + aes_mbedtls_init (&aes_engine); + aes_engine.base.set_key (&aes_engine.base, secret, secret_length); + + int stat = aes_engine.base.decrypt_data (&aes_engine.base, ciphertext, ciphertext_size, + tag, AESIV, AESIV_SIZE, plaintext, ciphertext_size); + *state = 5; + if(stat != 0){ + return PIT_CRYPTO_DECRYPTION_FAILED; + } + return SUCESS; +} + +/** + * A function to generate a random string representing OTP. Additionally, this function will encrypt that OTP using AES-GCM encryption, using the secret key for the AES encryption. + * @param secret The secret key to encrypt the OTP with + * @param secret_size The size of the secret key + * @param AESIV An IV to use for encryption. A 12-byte IV is best (meets NIST standards) + * @param AESIV_SIZE The size of the IV used for encryption + * @param tag The output buffer to hold the GCM authentication tag. All tags will be 16 bytes + * @param OTP An output buffer to hold a randomly generated OTP into + * @param OTPSize The size the randomly generated OTP should be + * @param OTPs An initialized but empty buffer to hold the encrypted OTP in (OTPs and OTP will be the same size) + * @param state An int to hold the numerical value of the state + * @return 1 on success +*/ +int pit_OTPgen(uint8_t *secret, size_t secret_size, uint8_t *AESIV, size_t aesiv_size, uint8_t *tag, uint8_t *OTP, size_t OTPsize, uint8_t *OTPs, int *state){ + struct rng_engine_mbedtls engine; + int status; + status = rng_mbedtls_init (&engine); + status = engine.base.generate_random_buffer (&engine.base, OTPsize, OTP); + if(status != 0){ + return PIT_CRYPTO_OTP_GENERATION_FAILED; + } + +status = pit_encryption(OTP, OTPsize, secret, secret_size, AESIV, aesiv_size, tag, OTPs, state); + +if(status != 1){ + return PIT_CRYPTO_ENCRYPTION_FAILED; +} + +*state = 6; +return SUCESS; +} + +/** + * Decrypts an encrypted OTP and compares it to a valid version of the OTP. If the OTP decrypts successfully and matches the valid OTP, the result parameter contains true. + * @param secret The secret key used to decrypt OTPs + * @param secret_size The size of the secret key + * @param AESIV An IV to use for decryption. Must be the same as the IV provided to encrypt + * @param AESIV_SIZE The size of the IV used for encryption + * @param tag The AES-GCM tag for the ciphertext + * @param OTPs A full buffer holding the value for OTPs (an encrypted OTP to validate against) + * @param OTPs_size The size of OTPs + * @param valOTP OTP to be validated against the decrypted OTP + * @param result A boolean value to check whether the OTP was successfully validated + * @param An int to hold the numerical value of the state + * @return 1 on success +*/ +int pit_OTPvalidation(uint8_t * secret, size_t secret_size, uint8_t *AESIV, size_t AESIV_size, uint8_t *tag, uint8_t *OTPs, size_t OTPs_size, uint8_t *valOTP, bool *result, int *state){ + struct aes_engine_mbedtls aes_engine; + aes_mbedtls_init (&aes_engine); + aes_engine.base.set_key (&aes_engine.base, secret, secret_size); + + uint8_t plaintext[OTPs_size]; + int stat = aes_engine.base.decrypt_data (&aes_engine.base, OTPs, OTPs_size, + tag, AESIV, AESIV_size, plaintext, OTPs_size); + + if(stat != 0){ + return PIT_CRYPTO_DECRYPTION_FAILED; + } + bool flag = true; + + for(int i = 0; i < (int)OTPs_size; i++){ + if(plaintext[i] != valOTP[i]){ + flag = false; + break; + } + } + *result = flag; + *state = 7; + if(flag){ + return SUCESS; + } + return PIT_CRYPTO_OTP_INVALID; +} + + diff --git a/core/pit/pit_crypto.h b/core/pit/pit_crypto.h new file mode 100644 index 00000000..d7270783 --- /dev/null +++ b/core/pit/pit_crypto.h @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ + +#include +#include +#include +#include +#include +#include +#include "crypto/ecc.h" +#include "crypto/ecc_mbedtls.h" +#include "testing/crypto/ecc_testing.h" +#include "mbedtls/ecdh.h" + +#define SUCESS 1 + +/** + * Core Cyrpto functionalities to perform encrption and decryption. + */ + +int pit_keygenstate(size_t key_length, struct ecc_private_key *privkey, struct ecc_public_key *pubkey, int *state); + +int pit_secretkey(struct ecc_private_key *privkey, struct ecc_public_key *pubkey, uint8_t *secret, int *state); + +int pit_encryption(uint8_t *msg, size_t msg_size, uint8_t *secret, size_t secret_length, uint8_t *AESIV, size_t AESIV_SIZE, uint8_t *tag, uint8_t *ciphertext, int *state); + +int pit_decryption(uint8_t *ciphertext, size_t ciphertext_size, uint8_t *secret, size_t secret_length, uint8_t *AESIV, size_t AESIV_SIZE, uint8_t *tag, uint8_t *plaintext, int *state); + +/** + * OTP generation and validation functionalities. + */ +int pit_OTPgen(uint8_t *secret, size_t secret_size, uint8_t *AESIV, size_t AESIV_SIZE, uint8_t *tag, uint8_t *OTP, size_t OTPSize, uint8_t *OTPs, int *state); + +int pit_OTPvalidation(uint8_t * secret, size_t secret_size, uint8_t *AESIV, size_t AESIV_SIZE, uint8_t *tag, uint8_t *OTPs, size_t OTPs_size, uint8_t *valOTP, bool *result, int *state); + +#define PIT_CRYPTO_ERROR(code) ROT_ERROR (ROT_MODULE_PIT_CRYPTO, code) + +/** + * Error codes that can be generated by a hash or HMAC engine. + */ +enum { + PIT_CRYPTO_DECRYPTION_FAILED = PIT_CRYPTO_ERROR (0x00), /** Decryption failed*/ + PIT_CRYPTO_ENCRYPTION_FAILED = PIT_CRYPTO_ERROR (0x01), /** Encryption failed*/ + PIT_CRYPTO_SECRET_KEY_NOT_EXPECTED_LENGTH = PIT_CRYPTO_ERROR (0x02), /** Failed to compute secret key*/ + PIT_CRYPTO_KEY_GENERATION_FAILED = PIT_CRYPTO_ERROR (0x03), /** Failed to generate a keypair*/ + PIT_CRYPTO_OTP_GENERATION_FAILED = PIT_CRYPTO_ERROR (0x04), + PIT_CRYPTO_OTP_INVALID = PIT_CRYPTO_ERROR (0x05), /** SHOULD ALSO BE ERROR*/ +}; \ No newline at end of file diff --git a/core/status/module_id.h b/core/status/module_id.h index 1f19440e..17ed5488 100644 --- a/core/status/module_id.h +++ b/core/status/module_id.h @@ -152,6 +152,9 @@ enum { ROT_MODULE_AUTHORIZED_EXECUTION = 0x008c, /**< Execution context for authorized operations. */ ROT_MODULE_SPDM_VDM_PROTOCOL = 0x008d, /**< SPDM vendor defined messages protocol. */ ROT_MODULE_SPDM_PCISIG_PROTOCOL = 0x008e, /**< SPDM PCISIG messages protocol. */ + ROT_MODULE_PIT_CRYPTO = 0x0063, /**< Handel Error from PIT Crypto file. */ + ROT_MODULE_PIT_I2C = 0X0064, /**< Handel Error from PIT Client file. */ + ROT_MODULE_PIT = 0X0065, /**< Handel Error from PIT file. */ }; diff --git a/core/testing/pit_tests/pit_crypto_tests.c b/core/testing/pit_tests/pit_crypto_tests.c new file mode 100644 index 00000000..5811ea4e --- /dev/null +++ b/core/testing/pit_tests/pit_crypto_tests.c @@ -0,0 +1,299 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ + +#include +#include +#include +#include +#include +#include "platform.h" +#include "testing.h" +#include "crypto/ecc.h" +#include "crypto/ecc_mbedtls.h" +#include "testing/crypto/ecc_testing.h" +#include "crypto/rng_mbedtls.h" +#include "asn1/base64_mbedtls.h" +#include "pit/pit.h" +#include "pit/pit_crypto.h" + +TEST_SUITE_LABEL ("pit_crypto"); +uint8_t AES_IV_TESTING[] = { + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b +}; + + + +static void test_keygenstate(CuTest *test){ + TEST_START; + struct ecc_private_key priv_key; + struct ecc_public_key pub_key; + size_t keysize = (256 / 8); + int state = -1; + + int status = pit_keygenstate(keysize, &priv_key, &pub_key, &state); + CuAssertPtrNotNull(test, pub_key.context); + CuAssertPtrNotNull(test, priv_key.context); + CuAssertIntEquals(test, 1, status); + CuAssertIntEquals(test, 1, state); + + +} + +static void test_secretkey(CuTest *test){ + TEST_START; + size_t keysize = (256 / 8); + int state = -1; + struct ecc_private_key priv_key1; + struct ecc_public_key pub_key1; + struct ecc_private_key priv_key2; + struct ecc_public_key pub_key2; + + + struct ecc_engine_mbedtls engine; + ecc_mbedtls_init (&engine); + + int status = pit_keygenstate(keysize, &priv_key1, &pub_key1, &state); + CuAssertIntEquals(test, 1, status); + + status = pit_keygenstate(keysize, &priv_key2, &pub_key2, &state); + CuAssertIntEquals(test, 1, status); + + int shared_length = engine.base.get_shared_secret_max_length(&engine.base, &priv_key2); + int shared_length2 = engine.base.get_shared_secret_max_length(&engine.base, &priv_key1); + ecc_mbedtls_release(&engine); + + + CuAssertIntEquals(test, shared_length2, shared_length); + + uint8_t secret1[shared_length]; + uint8_t secret2[shared_length]; + + status = pit_secretkey(&priv_key1, &pub_key2, secret1, &state); + CuAssertIntEquals(test, 1, status); + + status = pit_secretkey(&priv_key2, &pub_key1, secret2, &state); + CuAssertIntEquals(test, 1, status); + + status = testing_validate_array (secret1, secret2, sizeof(secret1)); + CuAssertIntEquals (test, 0, status); + +} + +static void test_encryptionPID(CuTest *test){ + TEST_START; + size_t keysize = (256 / 8); + int state = -1; + struct ecc_private_key priv_key1; + struct ecc_public_key pub_key1; + struct ecc_private_key priv_key2; + struct ecc_public_key pub_key2; + + struct ecc_engine_mbedtls engine; + ecc_mbedtls_init (&engine); + + int status = pit_keygenstate(keysize, &priv_key1, &pub_key1, &state); + CuAssertIntEquals(test, 1, status); + + status = pit_keygenstate(keysize, &priv_key2, &pub_key2, &state); + CuAssertIntEquals(test, 1, status); + + int shared_length = engine.base.get_shared_secret_max_length(&engine.base, &priv_key2); + int shared_length2 = engine.base.get_shared_secret_max_length(&engine.base, &priv_key1); + ecc_mbedtls_release(&engine); + + + CuAssertIntEquals(test, shared_length2, shared_length); + + uint8_t secret1[shared_length]; + uint8_t secret2[shared_length]; + + status = pit_secretkey(&priv_key1, &pub_key2, secret1, &state); + CuAssertIntEquals(test, 1, status); + + status = pit_secretkey(&priv_key2, &pub_key1, secret2, &state); + CuAssertIntEquals(test, 1, status); + + status = testing_validate_array (secret1, secret2, sizeof(secret1)); + CuAssertIntEquals (test, 0, status); + + int msg_length = 128; + uint8_t msg[128] = "Hi!"; + uint8_t ciphertext[msg_length]; + uint8_t tag[16]; //Tags are always length 16 + + status = pit_encryption(msg, msg_length, secret1, sizeof(secret1), AES_IV_TESTING, sizeof(AES_IV_TESTING), tag, ciphertext, &state); + + CuAssertIntEquals(test, 1, status); + CuAssertIntEquals(test, 4, state); + +} + +static void test_decryption(CuTest *test){ + TEST_START; + size_t keysize = (256 / 8); + int state = -1; + struct ecc_private_key priv_key1; + struct ecc_public_key pub_key1; + struct ecc_private_key priv_key2; + struct ecc_public_key pub_key2; + + + struct ecc_engine_mbedtls engine; + ecc_mbedtls_init (&engine); + + + + int status = pit_keygenstate(keysize, &priv_key1, &pub_key1, &state); + CuAssertIntEquals(test, 1, status); + + status = pit_keygenstate(keysize, &priv_key2, &pub_key2, &state); + CuAssertIntEquals(test, 1, status); + + int shared_length = engine.base.get_shared_secret_max_length(&engine.base, &priv_key2); + ecc_mbedtls_release(&engine); + + + + uint8_t secret1[shared_length]; + + status = pit_secretkey(&priv_key1, &pub_key2, secret1, &state); + CuAssertIntEquals(test, 1, status); + + int msg_length = 128; + uint8_t msg[128] = "Hi there!"; + uint8_t ciphertext[msg_length]; + uint8_t tag[16]; //Tags are always length 16 + + status = pit_encryption(msg, msg_length, secret1, sizeof(secret1), AES_IV_TESTING, sizeof(AES_IV_TESTING), tag, ciphertext, &state); + + uint8_t decrypted_msg[msg_length]; + status = pit_decryption(ciphertext, sizeof(ciphertext), secret1, sizeof(secret1), AES_IV_TESTING, sizeof(AES_IV_TESTING), tag, decrypted_msg, &state); + CuAssertIntEquals(test, 1, status); + + status = testing_validate_array (msg, decrypted_msg, sizeof(decrypted_msg)); + CuAssertIntEquals (test, 0, status); + +} + +static void test_randomness(CuTest *test){ + TEST_START; + struct rng_engine_mbedtls engine; + uint8_t buffer[32] = {0}; + uint8_t zero[32] = {0}; + int status; + + TEST_START; + + status = rng_mbedtls_init (&engine); + CuAssertIntEquals (test, 0, status); + + status = engine.base.generate_random_buffer (&engine.base, 32, buffer); + CuAssertIntEquals (test, 0, status); + + status = testing_validate_array (zero, buffer, sizeof (buffer)); + CuAssertTrue (test, (status != 0)); + rng_mbedtls_release (&engine); + +} + +static void test_OTPgen(CuTest *test){ + TEST_START; + size_t keysize = (256 / 8); + int state = -1; + struct ecc_private_key priv_key1; + struct ecc_public_key pub_key1; + struct ecc_private_key priv_key2; + struct ecc_public_key pub_key2; + + + struct ecc_engine_mbedtls engine; + ecc_mbedtls_init (&engine); + + + + int status = pit_keygenstate(keysize, &priv_key1, &pub_key1, &state); + CuAssertIntEquals(test, 1, status); + + status = pit_keygenstate(keysize, &priv_key2, &pub_key2, &state); + CuAssertIntEquals(test, 1, status); + + int shared_length = engine.base.get_shared_secret_max_length(&engine.base, &priv_key2); + ecc_mbedtls_release (&engine); + uint8_t secret[shared_length]; + + status = pit_secretkey(&priv_key1, &pub_key2, secret, &state); + CuAssertIntEquals(test, 1, status); + + size_t OTPsize = 32; + uint8_t tag[16]; + uint8_t OTP[OTPsize]; + uint8_t OTPs[OTPsize]; + status = pit_OTPgen(secret, sizeof(secret), AES_IV_TESTING, sizeof(AES_IV_TESTING), tag, OTP, OTPsize, OTPs, &state); + CuAssertPtrNotNull(test, OTPs); + CuAssertIntEquals(test, 1, status); + CuAssertIntEquals(test, 6, state); +} + +static void test_OTPvalidation(CuTest *test){ + TEST_START; + size_t keysize = (256 / 8); + int state = -1; + struct ecc_private_key priv_key1; + struct ecc_public_key pub_key1; + struct ecc_private_key priv_key2; + struct ecc_public_key pub_key2; + + + struct ecc_engine_mbedtls engine; + ecc_mbedtls_init (&engine); + + + + int status = pit_keygenstate(keysize, &priv_key1, &pub_key1, &state); + CuAssertIntEquals(test, 1, status); + + status = pit_keygenstate(keysize, &priv_key2, &pub_key2, &state); + CuAssertIntEquals(test, 1, status); + + int shared_length = engine.base.get_shared_secret_max_length(&engine.base, &priv_key2); + ecc_mbedtls_release (&engine); + uint8_t secret[shared_length]; + + status = pit_secretkey(&priv_key1, &pub_key2, secret, &state); + CuAssertIntEquals(test, 1, status); + + size_t OTPsize = 32; + uint8_t tag[16]; + uint8_t OTP[OTPsize]; + uint8_t OTPs[OTPsize]; + status = pit_OTPgen(secret, sizeof(secret), AES_IV_TESTING, sizeof(AES_IV_TESTING), tag, OTP, OTPsize, OTPs, &state); + CuAssertPtrNotNull(test, OTPs); + CuAssertIntEquals(test, 1, status); + CuAssertIntEquals(test, 6, state); + + bool result; + status = pit_OTPvalidation(secret, sizeof(secret), AES_IV_TESTING, sizeof(AES_IV_TESTING), tag, OTPs, sizeof(OTPs), OTP, &result, &state); + + CuAssertIntEquals(test, 1, result); + CuAssertIntEquals(test, 7, state); + CuAssertIntEquals(test, 1, status); +} + + + + + +TEST_SUITE_START (pit_crypto); +TEST (test_keygenstate); +TEST (test_secretkey); +TEST (test_encryptionPID); +TEST (test_randomness); +TEST (test_OTPgen); +TEST (test_OTPvalidation); +TEST (test_decryption); +TEST_SUITE_END; \ No newline at end of file diff --git a/core/testing/pit_tests/pit_crypto_tests.h b/core/testing/pit_tests/pit_crypto_tests.h new file mode 100644 index 00000000..25d3dcc0 --- /dev/null +++ b/core/testing/pit_tests/pit_crypto_tests.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ + +#include "testing.h" +#include "platform_all_tests.h" +#include "common/unused.h" + +static void add_all_pit_crypto_tests (CuSuite *suite) +{ +TESTING_RUN_SUITE (pit_crypto); +} \ No newline at end of file diff --git a/core/testing/pit_tests/pit_test.c b/core/testing/pit_tests/pit_test.c new file mode 100644 index 00000000..9630d54c --- /dev/null +++ b/core/testing/pit_tests/pit_test.c @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ + +#include +#include +#include +#include +#include +#include "platform.h" +#include "testing.h" +#include "testing/crypto/ecc_testing.h" +#include "pit/pit.h" + +TEST_SUITE_LABEL ("pit"); + +static void test_pit_lock(CuTest *test){ + TEST_START; + + uint8_t secret[32]; + pit_Lock(secret); + int state = get_state(); + printf("Device is Locked.\n"); + CuAssertIntEquals(test, 0, state); +} + +static void test_pit_unlock(CuTest *test){ + TEST_START; + int status = pit_Unlock(); + CuAssertIntEquals(test, 1, status); + int state = get_state(); + CuAssertIntEquals(test, 7, state); +} + + +static void test_pit_get_OTPs(CuTest *test){ + TEST_START; + uint8_t my_OTPs[128]; + int status = get_OTPs(my_OTPs); + CuAssertIntEquals(test, 1, status); +} + +TEST_SUITE_START (pit); +TEST (test_pit_lock); +TEST (test_pit_unlock); +TEST (test_pit_get_OTPs); +TEST_SUITE_END; \ No newline at end of file diff --git a/core/testing/pit_tests/pit_test.h b/core/testing/pit_tests/pit_test.h new file mode 100644 index 00000000..8c7a5d42 --- /dev/null +++ b/core/testing/pit_tests/pit_test.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +/* + Developed by AMI Inc. & Colorado State University. + Contact person: Rakesh Podder. Email: rakeshpodder3@gmail.com +*/ + +#include "testing.h" +#include "platform_all_tests.h" +#include "common/unused.h" + +static void add_all_pit_tests (CuSuite *suite) +{ +TESTING_RUN_SUITE (pit); +} \ No newline at end of file