I am using TPM Java library provided by Microsoft. Connection is working for simulator. Stuck in how to encrypt string using TPM Endrosment public key and decrypt using TPM Endrosment Private key.
Below is the code which is incorrect functionality, Where TPM private EK is not visible outside world then how to decrypt using private EK.
public class Sample {
boolean usesTbs;
Tpm tpm;
Cipher cipher;
public static byte[] nullVec = new byte[36];
private static final String SHA_256 = "SHA-256";
private static final String EQUALS = "=";
private final String registrationId;
private TPMT_PUBLIC ekPublic = null;
private TPMT_PUBLIC srkPublic = null;
private TPM2B_PUBLIC idKeyPub = null;
private static final TPM_HANDLE SRK_PERSISTENT_HANDLE = TPM_HANDLE.persistent(0x00000001);
private static final TPM_HANDLE EK_PERSISTENT_HANDLE = TPM_HANDLE.persistent(0x00010001);
private static final TPM_HANDLE ID_KEY_PERSISTENT_HANDLE = TPM_HANDLE.persistent(0x00000100);
private static final TPMT_SYM_DEF_OBJECT AES_128_SYM_DEF = new TPMT_SYM_DEF_OBJECT(TPM_ALG_ID.AES, 128, TPM_ALG_ID.CFB);
private static final TPMT_PUBLIC EK_TEMPLATE = new TPMT_PUBLIC(
// TPMI_ALG_HASH nameAlg
TPM_ALG_ID.SHA256,
// TPMA_OBJECT objectAttributes
new TPMA_OBJECT(TPMA_OBJECT.restricted, TPMA_OBJECT.decrypt, TPMA_OBJECT.fixedTPM, TPMA_OBJECT.fixedParent,
TPMA_OBJECT.adminWithPolicy, TPMA_OBJECT.sensitiveDataOrigin),
// TPM2B_DIGEST authPolicy
javax.xml.bind.DatatypeConverter.parseHexBinary("837197674484b3f81a90cc8d46a5d724fd52d76e06520b64f2a1da1b331469aa"),
// TPMU_PUBLIC_PARMS parameters
new TPMS_RSA_PARMS(AES_128_SYM_DEF, new TPMS_NULL_ASYM_SCHEME(), 2048, 0),
// TPMU_PUBLIC_ID unique
new TPM2B_PUBLIC_KEY_RSA());
private static final TPMT_PUBLIC SRK_TEMPLATE = new TPMT_PUBLIC(
// TPMI_ALG_HASH nameAlg
TPM_ALG_ID.SHA256,
// TPMA_OBJECT objectAttributes
new TPMA_OBJECT(TPMA_OBJECT.restricted, TPMA_OBJECT.decrypt, TPMA_OBJECT.fixedTPM, TPMA_OBJECT.fixedParent,
TPMA_OBJECT.noDA, TPMA_OBJECT.userWithAuth, TPMA_OBJECT.sensitiveDataOrigin),
// TPM2B_DIGEST authPolicy
new byte[0],
// TPMU_PUBLIC_PARMS parameters
new TPMS_RSA_PARMS(AES_128_SYM_DEF, new TPMS_NULL_ASYM_SCHEME(), 2048, 0),
// TPMU_PUBLIC_ID unique
new TPM2B_PUBLIC_KEY_RSA());
public TpmSample() throws Exception {
System.out.println("===> PATH = " + System.getenv("PATH"));
System.out.println("===> path = " + System.getenv("path"));
usesTbs = CmdLine.isOptionPresent("tbs", "t");
System.out.println("Connecting to " + (usesTbs ? "OS TPM" : "TPM Simulator"));
tpm = usesTbs ? TpmFactory.platformTpm() : TpmFactory.localTpmSimulator();
clearPersistent(tpm, EK_PERSISTENT_HANDLE, "EK");
clearPersistent(tpm, SRK_PERSISTENT_HANDLE, "SRK");
ekPublic = createPersistentPrimary(tpm, EK_PERSISTENT_HANDLE, TPM_RH.OWNER, EK_TEMPLATE, "EK");
srkPublic = createPersistentPrimary(tpm, SRK_PERSISTENT_HANDLE, TPM_RH.OWNER, SRK_TEMPLATE, "SRK");
//SRS_SecurityProviderTPMEmulator_25_002: [ The constructor shall set the registration Id to null if none was provided. ]
this.registrationId = null;
}
private void cleanSlots(TPM_HT slotType) {
GetCapabilityResponse caps = tpm.GetCapability(TPM_CAP.HANDLES, slotType.toInt() << 24, 8);
TPML_HANDLE handles = (TPML_HANDLE) caps.capabilityData;
if (handles.handle.length == 0)
System.out.println("No dangling " + slotType.name() + " handles");
else
for (TPM_HANDLE h : handles.handle) {
System.out.printf("Dangling " + slotType.name() + " handle 0x%08X\n", h.handle);
tpm.FlushContext(h);
}
}
public byte[] getEndrosmentPrivateKey() {
return (new TPM2B_PRIVATE()).toTpm();
}
public byte[] getEndorsementKey() {
//SRS_SecurityProviderTPMEmulator_25_032: [ This method shall return the TPM2B_PUBLIC form of EK. ]
return (new TPM2B_PUBLIC(ekPublic)).toTpm();
}
public byte[] getStorageRootKey() {
//SRS_SecurityProviderTPMEmulator_25_033: [ This method shall return the TPM2B_PUBLIC form of SRK. ]
return (new TPM2B_PUBLIC(srkPublic)).toTpm();
}
private TPMT_PUBLIC createPersistentPrimary(Tpm tpm, TPM_HANDLE hPersistent, TPM_RH hierarchy, TPMT_PUBLIC inPub, String primaryRole) throws Exception {
ReadPublicResponse rpResp = tpm._allowErrors().ReadPublic(hPersistent);
if (rpResp == null) {
throw new Exception("ReadPublicResponse cannot be null");
}
TPM_RC rc = tpm._getLastResponseCode();
if (rc == TPM_RC.SUCCESS) {
// TODO: Check if the public area of the existing key matches the requested one
return rpResp.outPublic;
}
if (rc != TPM_RC.HANDLE) {
throw new Exception("Unexpected failure {" + rc.name() + "} of TPM2_ReadPublic for {" + primaryRole + "}");
}
TPMS_SENSITIVE_CREATE sens = new TPMS_SENSITIVE_CREATE(new byte[0], new byte[0]);
CreatePrimaryResponse cpResp = tpm.CreatePrimary(TPM_HANDLE.from(hierarchy), sens, inPub,
new byte[0], new TPMS_PCR_SELECTION[0]);
// System.out.println("RSA Primary Key: \n" + cpResp.toString());
if (cpResp == null) {
throw new Exception("CreatePrimaryResponse cannot be null");
}
tpm.EvictControl(TPM_HANDLE.from(TPM_RH.OWNER), cpResp.handle, hPersistent);
tpm.FlushContext(cpResp.handle);
return cpResp.outPublic;
}
private void clearPersistent(Tpm tpm, TPM_HANDLE hPersistent, String keyRole) throws Exception {
tpm._allowErrors().ReadPublic(hPersistent);
TPM_RC rc = tpm._getLastResponseCode();
if (rc == TPM_RC.SUCCESS) {
tpm.EvictControl(TPM_HANDLE.from(TPM_RH.OWNER), hPersistent, hPersistent);
} else if (rc != TPM_RC.HANDLE) {
throw new Exception("Unexpected failure for {" + rc.name() + "} of TPM2_ReadPublic for " + keyRole + " 0x" + hPersistent.handle);
}
}
public SecretKeySpec setKey(byte[] key) {
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance(SHA_256);
key = digest.digest(key);
key = Arrays.copyOf(key, 16);
return new SecretKeySpec(key, "AES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
public byte[] encrypt(String data, byte[] publicEKey) throws Exception {
SecretKeySpec secretKeySpec = setKey(publicEKey);
cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(new byte[16]));
byte[] cipherText = cipher.doFinal(data.getBytes("UTF-8"));
System.out.println("Encrypted Data from Method:->" + new String(cipherText, "UTF-8"));
return cipherText;
}
public byte[] decrypt(byte[] cipherText, byte[] privateEKey) throws Exception {
SecretKeySpec secretKeySpec = setKey(privateEKey);
Cipher cipherDecrypt = Cipher.getInstance("AES/CFB/NoPadding");
cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(new byte[16]));
byte[] decipheredText = cipher.doFinal(cipherText);
System.out.println("Decrypted Data from Method:-> " + new String(decipheredText));
return decipheredText;
}
public static void main(String[] args) throws Exception {
String data = "asdfqwert";
Sample tpmSample = new Sample();
tpmSample.cleanSlots(TPM_HT.TRANSIENT);
tpmSample.cleanSlots(TPM_HT.LOADED_SESSION);
tpmSample.getTpmInformation();
System.out.println("Endrosment Key :->" + new String(org.bouncycastle.util.encoders.Base64.encode(tpmSample.getEndorsementKey())));
System.out.println("Private Endrosment Key :->" + new String(org.bouncycastle.util.encoders.Base64.encode(tpmSample.getEndrosmentPrivateKey())));
byte[] publicEKey = new String(Base64.encode(tpmSample.getEndorsementKey())).getBytes("UTF-8");
byte[] privateEKey = new String(Base64.encode(tpmSample.getEndrosmentPrivateKey())).getBytes("UTF-8");
System.out.println("Original Data ->" + data);
byte[] enc = tpmSample.encrypt(data, publicEKey);
tpmSample.decrypt(enc, privateEKey);
}
}
The Endorsement Key(EK) is not inteded to be used directly for encryption. Instead, you are expected to create a StorageKey(SK) or Storage Key Hierarchy using a Primary Key. Then, create another key for encryption and use that key to encryption portion of your hard drive or file.
This can be achieved using TPM2 Seal/Unseal. If it is a matter of a single string you could cheat away using TPM2 Encrypt/Decrypt, but that's not recommended. Better to have a file with the secret and encrypt that file.
What I could recommend is to check this out for some foundation about TPM https://google.github.io/tpm-js/ and here is a nice discussion about the difference between using Seal/Unseal and EncryptDecrypt https://developers.tpm.dev/posts/8628948
These two resources should clear your confusion and then it is a matter of writing code. I am not sure only if Java and the Microsoft TPM2.0 stack are the quickest way to achieve what you want, but once you get the concept right, then it is really just implementation :)
User contributions licensed under CC BY-SA 3.0