From 6d72f782814086eb5f73d85865bfe677d6434a7a Mon Sep 17 00:00:00 2001 From: waner Date: Wed, 1 Apr 2026 16:47:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9Ejna=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crypto/pcie/PcieSessionTemplate.java | 36 ++ .../crypto/pcie/jna/PcieNativeLibrary.java | 34 +- .../crypto/pcie/jna/SdfFirmwareInfo.java | 15 + .../crypto/pcie/jna/SdfeIkComponent.java | 16 + .../pcie/model/EccInternalDecryptRequest.java | 32 ++ .../pcie/model/EccInternalEncryptRequest.java | 32 ++ .../crypto/pcie/model/FirmwareInfoResult.java | 32 ++ .../crypto/pcie/model/IkSignRequest.java | 32 ++ .../crypto/pcie/model/IkVerifyRequest.java | 32 ++ .../model/ImportEncKeyPairRsaRequest.java | 41 -- .../pcie/service/JnaPcieCryptoService.java | 256 +++++++++-- .../pcie/service/MockPcieCryptoService.java | 108 ++++- .../pcie/service/PcieCryptoService.java | 391 ++++++++++++++++- .../controller/CryptoCardController.java | 9 - ...ortEncryptedKeyPairRsaInternalRequest.java | 51 --- .../support/crypto/CryptoRequestMapper.java | 11 - .../modules/mk/controller/LmkController.java | 1 + .../modules/mk/dto/MasterKeyPacketIkPart.java | 24 + .../mk/service/impl/LmkServiceImpl.java | 86 +++- .../service/JnaPcieCryptoServiceTest.java | 409 ++++++++++++++++++ .../controller/CryptoCardControllerTest.java | 9 + .../modules/mk/service/LmkServiceTest.java | 74 +++- 22 files changed, 1527 insertions(+), 204 deletions(-) create mode 100644 src/main/java/com/cisd/tms/integration/crypto/pcie/jna/SdfFirmwareInfo.java create mode 100644 src/main/java/com/cisd/tms/integration/crypto/pcie/jna/SdfeIkComponent.java create mode 100644 src/main/java/com/cisd/tms/integration/crypto/pcie/model/EccInternalDecryptRequest.java create mode 100644 src/main/java/com/cisd/tms/integration/crypto/pcie/model/EccInternalEncryptRequest.java create mode 100644 src/main/java/com/cisd/tms/integration/crypto/pcie/model/FirmwareInfoResult.java create mode 100644 src/main/java/com/cisd/tms/integration/crypto/pcie/model/IkSignRequest.java create mode 100644 src/main/java/com/cisd/tms/integration/crypto/pcie/model/IkVerifyRequest.java delete mode 100644 src/main/java/com/cisd/tms/integration/crypto/pcie/model/ImportEncKeyPairRsaRequest.java delete mode 100644 src/main/java/com/cisd/tms/modules/device/dto/crypto/request/CryptoImportEncryptedKeyPairRsaInternalRequest.java diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/PcieSessionTemplate.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/PcieSessionTemplate.java index 97f66ab..edfa613 100644 --- a/src/main/java/com/cisd/tms/integration/crypto/pcie/PcieSessionTemplate.java +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/PcieSessionTemplate.java @@ -27,6 +27,11 @@ public class PcieSessionTemplate { T apply(PcieNativeLibrary lib, Pointer deviceHandle, Pointer sessionHandle); } + @FunctionalInterface + public interface TwoSessionCallback { + T apply(PcieNativeLibrary lib, Pointer deviceHandle, Pointer sessionHandleFrom, Pointer sessionHandleTo); + } + private static final Logger log = LoggerFactory.getLogger(PcieSessionTemplate.class); private final CryptoCardProperties properties; @@ -71,6 +76,27 @@ public class PcieSessionTemplate { } } + public T withTwoSessions(String apiName, TwoSessionCallback callback) { + synchronized (lock) { + PcieNativeLibrary lib = ensureLibraryLoaded(); + Pointer deviceHandle = ensureSharedDeviceOpened(apiName, lib); + Pointer sessionFrom = tryOpenSession(apiName, lib, deviceHandle); + if (sessionFrom == null) { + resetSharedDevice(lib); + deviceHandle = ensureSharedDeviceOpened(apiName, lib); + sessionFrom = openSessionOrThrow(apiName, lib, deviceHandle); + } + Pointer sessionTo = openSessionOrThrow(apiName, lib, deviceHandle); + + try { + return callback.apply(lib, deviceHandle, sessionFrom, sessionTo); + } finally { + closeSessionQuietly(apiName, lib, sessionTo); + closeSessionQuietly(apiName, lib, sessionFrom); + } + } + } + public void ensureSuccess(String apiName, int retCode) { if (retCode != 0) { throw new PcieCryptoException(apiName, retCode, errorMapper.toMessage(retCode)); @@ -146,6 +172,16 @@ public class PcieSessionTemplate { return sessionRef.getValue(); } + private void closeSessionQuietly(String apiName, PcieNativeLibrary lib, Pointer sessionHandle) { + if (sessionHandle == null) { + return; + } + int closeSessionRc = lib.SDF_CloseSession(sessionHandle); + if (closeSessionRc != 0) { + log.warn("{} close session failed: {}", apiName, errorMapper.toMessage(closeSessionRc)); + } + } + private void resetSharedDevice(PcieNativeLibrary lib) { closeSharedDevice(lib); } diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/PcieNativeLibrary.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/PcieNativeLibrary.java index a2fd7da..7bfbc43 100644 --- a/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/PcieNativeLibrary.java +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/PcieNativeLibrary.java @@ -200,10 +200,6 @@ public interface PcieNativeLibrary extends Library { int SDFE_ImportEncKeyPair_ECC(Pointer hSessionHandle, int keyIndex, EnvelopedKeyBlob envelopedKeyBlob); - int SDFE_ImportEncKeyPair_RSA(Pointer hSessionHandle, int keyIndex, int symAlgId, - byte[] wrappedKey, int wrappedKeyLen, - byte[] encryptedData, int encryptedDataLen); - int SDFE_UpdateBackedKey(Pointer hSessionHandle, byte[] oldData, int oldDataLength, byte[] newData, IntByReference newDataLength); @@ -231,6 +227,18 @@ public interface PcieNativeLibrary extends Library { int SDFE_RecoverIK(Pointer hSessionHandle, int keyType); + int SDFE_BackupIK_EX(Pointer hSessionHandle, int keyType, SdfeIkComponent ikComponent); + + int SDFE_RecoverIK_EX(Pointer hSessionHandle, int keyType, SdfeIkComponent ikComponent); + + int SDFE_ExportIKPublicKey(Pointer hSessionHandle, int ikType, EccRefPublicKey publicKey); + + int SDFE_ExportIKMac(Pointer hSessionHandle, int ikType, byte[] mac); + + int SDFE_SignIK(Pointer hSessionHandle, int ikType, byte[] data, int dataLength, EccSignature signature); + + int SDFE_VerifyIK(Pointer hSessionHandle, int ikType, byte[] data, int dataLength, EccSignature signature); + int SDFE_DestroyIK(Pointer hSessionHandle, int keyType); int SDFE_StatusIK(Pointer hSessionHandle, int keyType, IntByReference keyState); @@ -264,4 +272,22 @@ public interface PcieNativeLibrary extends Library { int SDFE_HmacUpdate(Pointer hSessionHandle, byte[] data, int dataLength); int SDFE_HmacFinal(Pointer hSessionHandle, byte[] hmac, IntByReference hmacLength); + + int SDFE_GetFirmwareInfo(Pointer hSessionHandle, SdfFirmwareInfo firmwareInfo); + + int SDFE_HashCopy(Pointer hSessionHandleTo, Pointer hSessionHandleFrom); + + int SDFE_Encrypt(Pointer hSessionHandle, byte[] key, int keyLength, int algId, byte[] iv, + byte[] data, int dataLength, byte[] encData, IntByReference encDataLength); + + int SDFE_Decrypt(Pointer hSessionHandle, byte[] key, int keyLength, int algId, byte[] iv, + byte[] encData, int encDataLength, byte[] data, IntByReference dataLength); + + int SDFE_Hash(Pointer hSessionHandle, int algId, byte[] data, int dataLength, + byte[] hash, IntByReference hashLength); + + int SDFE_InternalEncrypt_ECC(Pointer hSessionHandle, int keyIndex, byte[] data, int dataLength, EccCipher encData); + + int SDFE_InternalDecrypt_ECC(Pointer hSessionHandle, int keyIndex, EccCipher encData, + byte[] data, IntByReference dataLength); } diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/SdfFirmwareInfo.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/SdfFirmwareInfo.java new file mode 100644 index 0000000..9cf1c5e --- /dev/null +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/SdfFirmwareInfo.java @@ -0,0 +1,15 @@ +package com.cisd.tms.integration.crypto.pcie.jna; + +import com.sun.jna.Structure; + +@Structure.FieldOrder({"bomInfo", "gd32Info", "n32s033Info"}) +public class SdfFirmwareInfo extends Structure { + + public byte[] bomInfo = new byte[5]; + public byte[] gd32Info = new byte[5]; + public byte[] n32s033Info = new byte[5]; + + public SdfFirmwareInfo() { + super(ALIGN_NONE); + } +} diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/SdfeIkComponent.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/SdfeIkComponent.java new file mode 100644 index 0000000..db4dcc2 --- /dev/null +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/jna/SdfeIkComponent.java @@ -0,0 +1,16 @@ +package com.cisd.tms.integration.crypto.pcie.jna; + +import com.sun.jna.Structure; + +@Structure.FieldOrder({"component", "priMac", "pubkey", "pubMac"}) +public class SdfeIkComponent extends Structure { + + public byte[] component = new byte[3 * EccRefPublicKey.MAX_LEN]; + public byte[] priMac = new byte[8]; + public EccRefPublicKey pubkey = new EccRefPublicKey(); + public byte[] pubMac = new byte[8]; + + public SdfeIkComponent() { + super(ALIGN_NONE); + } +} diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/model/EccInternalDecryptRequest.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/EccInternalDecryptRequest.java new file mode 100644 index 0000000..20adbe7 --- /dev/null +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/EccInternalDecryptRequest.java @@ -0,0 +1,32 @@ +package com.cisd.tms.integration.crypto.pcie.model; + +public class EccInternalDecryptRequest { + + private int keyIndex; + private byte[] cipherBlob; + private int outBufferSize; + + public int getKeyIndex() { + return keyIndex; + } + + public void setKeyIndex(int keyIndex) { + this.keyIndex = keyIndex; + } + + public byte[] getCipherBlob() { + return cipherBlob; + } + + public void setCipherBlob(byte[] cipherBlob) { + this.cipherBlob = cipherBlob; + } + + public int getOutBufferSize() { + return outBufferSize; + } + + public void setOutBufferSize(int outBufferSize) { + this.outBufferSize = outBufferSize; + } +} diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/model/EccInternalEncryptRequest.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/EccInternalEncryptRequest.java new file mode 100644 index 0000000..7d665f5 --- /dev/null +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/EccInternalEncryptRequest.java @@ -0,0 +1,32 @@ +package com.cisd.tms.integration.crypto.pcie.model; + +public class EccInternalEncryptRequest { + + private int keyIndex; + private byte[] data; + private int outBufferSize; + + public int getKeyIndex() { + return keyIndex; + } + + public void setKeyIndex(int keyIndex) { + this.keyIndex = keyIndex; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } + + public int getOutBufferSize() { + return outBufferSize; + } + + public void setOutBufferSize(int outBufferSize) { + this.outBufferSize = outBufferSize; + } +} diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/model/FirmwareInfoResult.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/FirmwareInfoResult.java new file mode 100644 index 0000000..b43e53b --- /dev/null +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/FirmwareInfoResult.java @@ -0,0 +1,32 @@ +package com.cisd.tms.integration.crypto.pcie.model; + +public class FirmwareInfoResult { + + private byte[] bomInfo; + private byte[] gd32Info; + private byte[] n32s033Info; + + public byte[] getBomInfo() { + return bomInfo; + } + + public void setBomInfo(byte[] bomInfo) { + this.bomInfo = bomInfo; + } + + public byte[] getGd32Info() { + return gd32Info; + } + + public void setGd32Info(byte[] gd32Info) { + this.gd32Info = gd32Info; + } + + public byte[] getN32s033Info() { + return n32s033Info; + } + + public void setN32s033Info(byte[] n32s033Info) { + this.n32s033Info = n32s033Info; + } +} diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/model/IkSignRequest.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/IkSignRequest.java new file mode 100644 index 0000000..ff2c028 --- /dev/null +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/IkSignRequest.java @@ -0,0 +1,32 @@ +package com.cisd.tms.integration.crypto.pcie.model; + +public class IkSignRequest { + + private int keyType; + private byte[] data; + private int signatureBufferSize; + + public int getKeyType() { + return keyType; + } + + public void setKeyType(int keyType) { + this.keyType = keyType; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } + + public int getSignatureBufferSize() { + return signatureBufferSize; + } + + public void setSignatureBufferSize(int signatureBufferSize) { + this.signatureBufferSize = signatureBufferSize; + } +} diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/model/IkVerifyRequest.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/IkVerifyRequest.java new file mode 100644 index 0000000..59af9a5 --- /dev/null +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/IkVerifyRequest.java @@ -0,0 +1,32 @@ +package com.cisd.tms.integration.crypto.pcie.model; + +public class IkVerifyRequest { + + private int keyType; + private byte[] data; + private byte[] signature; + + public int getKeyType() { + return keyType; + } + + public void setKeyType(int keyType) { + this.keyType = keyType; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } + + public byte[] getSignature() { + return signature; + } + + public void setSignature(byte[] signature) { + this.signature = signature; + } +} diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/model/ImportEncKeyPairRsaRequest.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/model/ImportEncKeyPairRsaRequest.java deleted file mode 100644 index 979952b..0000000 --- a/src/main/java/com/cisd/tms/integration/crypto/pcie/model/ImportEncKeyPairRsaRequest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.cisd.tms.integration.crypto.pcie.model; - -public class ImportEncKeyPairRsaRequest { - - private int keyIndex; - private int symAlgId; - private byte[] wrappedKey; - private byte[] encryptedData; - - public int getKeyIndex() { - return keyIndex; - } - - public void setKeyIndex(int keyIndex) { - this.keyIndex = keyIndex; - } - - public int getSymAlgId() { - return symAlgId; - } - - public void setSymAlgId(int symAlgId) { - this.symAlgId = symAlgId; - } - - public byte[] getWrappedKey() { - return wrappedKey; - } - - public void setWrappedKey(byte[] wrappedKey) { - this.wrappedKey = wrappedKey; - } - - public byte[] getEncryptedData() { - return encryptedData; - } - - public void setEncryptedData(byte[] encryptedData) { - this.encryptedData = encryptedData; - } -} diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/service/JnaPcieCryptoService.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/service/JnaPcieCryptoService.java index 0baf0a4..bc24677 100644 --- a/src/main/java/com/cisd/tms/integration/crypto/pcie/service/JnaPcieCryptoService.java +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/service/JnaPcieCryptoService.java @@ -15,12 +15,13 @@ import com.cisd.tms.integration.crypto.pcie.jna.PcieNativeLibrary; import com.cisd.tms.integration.crypto.pcie.jna.RsaRefPrivateKey; import com.cisd.tms.integration.crypto.pcie.jna.RsaRefPublicKey; import com.cisd.tms.integration.crypto.pcie.jna.SdfDeviceInfo; +import com.cisd.tms.integration.crypto.pcie.jna.SdfFirmwareInfo; import com.cisd.tms.integration.crypto.pcie.jna.SdfeDeviceConf; import com.cisd.tms.integration.crypto.pcie.jna.SdfeDeviceStatus; +import com.cisd.tms.integration.crypto.pcie.jna.SdfeIkComponent; import com.cisd.tms.integration.crypto.pcie.jna.SdfeKekComponent; import com.cisd.tms.integration.crypto.pcie.jna.SdfeLmkComponent; import com.cisd.tms.integration.crypto.pcie.jna.SdfeLoginState; -import com.cisd.tms.integration.crypto.pcie.jna.SydIkComponent; import com.cisd.tms.integration.crypto.pcie.model.AgreementDataAndKeyEccResult; import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult; import com.cisd.tms.integration.crypto.pcie.model.ChangePrivateKeyPasswordRequest; @@ -29,6 +30,8 @@ import com.cisd.tms.integration.crypto.pcie.model.DeviceCountResult; import com.cisd.tms.integration.crypto.pcie.model.DeviceInfoResult; import com.cisd.tms.integration.crypto.pcie.model.DeviceStatusResult; import com.cisd.tms.integration.crypto.pcie.model.DigestRequest; +import com.cisd.tms.integration.crypto.pcie.model.EccInternalDecryptRequest; +import com.cisd.tms.integration.crypto.pcie.model.EccInternalEncryptRequest; import com.cisd.tms.integration.crypto.pcie.model.EccExternalDecryptRequest; import com.cisd.tms.integration.crypto.pcie.model.EccExternalEncryptRequest; import com.cisd.tms.integration.crypto.pcie.model.EccExternalSignRequest; @@ -55,12 +58,14 @@ import com.cisd.tms.integration.crypto.pcie.model.GenerateKeyWithKekRequest; import com.cisd.tms.integration.crypto.pcie.model.GenerateKeyPairRequest; import com.cisd.tms.integration.crypto.pcie.model.HmacRequest; import com.cisd.tms.integration.crypto.pcie.model.HmacResult; +import com.cisd.tms.integration.crypto.pcie.model.FirmwareInfoResult; import com.cisd.tms.integration.crypto.pcie.model.ImportEncKeyPairEccRequest; -import com.cisd.tms.integration.crypto.pcie.model.ImportEncKeyPairRsaRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKekRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKeyWithIskEccRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKeyWithIskRsaRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKeyPairRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkSignRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest; import com.cisd.tms.integration.crypto.pcie.model.KekComponentRequest; import com.cisd.tms.integration.crypto.pcie.model.KeyStatusResult; import com.cisd.tms.integration.crypto.pcie.model.LoginStatusResult; @@ -655,36 +660,6 @@ public class JnaPcieCryptoService implements PcieCryptoService { }); } - @Override - public void importEncryptedKeyPairRsa(ImportEncKeyPairRsaRequest request) { - ImportEncKeyPairRsaRequest req = requireRequest("request", request); - int keyIndex = requireNonNegative("keyIndex", req.getKeyIndex()); - int symAlgId = requireValidAlgId("symAlgId", req.getSymAlgId()); - byte[] wrappedKey = requireNonEmptyBytes("wrappedKey", req.getWrappedKey()); - byte[] encryptedData = requireNonEmptyBytes("encryptedData", req.getEncryptedData()); - - try { - sessionTemplate.withSession("SDFE_ImportEncKeyPair_RSA", (lib, deviceHandle, sessionHandle) -> { - sessionTemplate.ensureSuccess( - "SDFE_ImportEncKeyPair_RSA", - lib.SDFE_ImportEncKeyPair_RSA( - sessionHandle, - keyIndex, - symAlgId, - wrappedKey, - wrappedKey.length, - encryptedData, - encryptedData.length - ) - ); - return null; - }); - } finally { - wipe(wrappedKey); - wipe(encryptedData); - } - } - @Override public BackupDataResult updateBackedKey(UpdateBackedKeyRequest request) { UpdateBackedKeyRequest req = requireRequest("request", request); @@ -778,6 +753,39 @@ public class JnaPcieCryptoService implements PcieCryptoService { }); } + @Override + public BackupDataResult exportIkPublicKey(int keyType, int outBufferSize) { + int safeKeyType = requireNonNegative("keyType", keyType); + int size = requirePositive("outBufferSize", outBufferSize); + + return sessionTemplate.withSession("SDFE_ExportIKPublicKey", (lib, deviceHandle, sessionHandle) -> { + EccRefPublicKey out = new EccRefPublicKey(); + if (size < out.size()) { + throw new IllegalArgumentException("outBufferSize must be >= " + out.size()); + } + sessionTemplate.ensureSuccess( + "SDFE_ExportIKPublicKey", + lib.SDFE_ExportIKPublicKey(sessionHandle, safeKeyType, out) + ); + byte[] outBytes = toBytes(out); + return toBackupResult("SDFE_ExportIKPublicKey", outBytes, outBytes.length); + }); + } + + @Override + public BackupDataResult exportIkMac(int keyType) { + int safeKeyType = requireNonNegative("keyType", keyType); + + return sessionTemplate.withSession("SDFE_ExportIKMac", (lib, deviceHandle, sessionHandle) -> { + byte[] out = new byte[8]; + sessionTemplate.ensureSuccess( + "SDFE_ExportIKMac", + lib.SDFE_ExportIKMac(sessionHandle, safeKeyType, out) + ); + return toBackupResult("SDFE_ExportIKMac", out, out.length); + }); + } + @Override public StandardKeyPairResult generateStandardRsaKeyPair(GenerateStandardRsaKeyPairRequest request) { GenerateStandardRsaKeyPairRequest req = requireRequest("request", request); @@ -1334,6 +1342,27 @@ public class JnaPcieCryptoService implements PcieCryptoService { }); } + @Override + public BackupDataResult signIk(IkSignRequest request) { + IkSignRequest req = requireRequest("request", request); + int keyType = requireNonNegative("keyType", req.getKeyType()); + byte[] data = requireBytes("data", req.getData()); + int signatureBufferSize = requirePositive("signatureBufferSize", req.getSignatureBufferSize()); + + return sessionTemplate.withSession("SDFE_SignIK", (lib, deviceHandle, sessionHandle) -> { + EccSignature signature = new EccSignature(); + if (signatureBufferSize < signature.size()) { + throw new IllegalArgumentException("signatureBufferSize must be >= " + signature.size()); + } + sessionTemplate.ensureSuccess( + "SDFE_SignIK", + lib.SDFE_SignIK(sessionHandle, keyType, data, data.length, signature) + ); + byte[] signatureBytes = toBytes(signature); + return toBackupResult("SDFE_SignIK", signatureBytes, signatureBytes.length); + }); + } + @Override public BackupDataResult eccExternalSign(EccExternalSignRequest request) { EccExternalSignRequest req = requireRequest("request", request); @@ -1372,6 +1401,22 @@ public class JnaPcieCryptoService implements PcieCryptoService { }); } + @Override + public void verifyIk(IkVerifyRequest request) { + IkVerifyRequest req = requireRequest("request", request); + int keyType = requireNonNegative("keyType", req.getKeyType()); + byte[] data = requireBytes("data", req.getData()); + EccSignature signature = toEccSignature("signature", req.getSignature()); + + sessionTemplate.withSession("SDFE_VerifyIK", (lib, deviceHandle, sessionHandle) -> { + sessionTemplate.ensureSuccess( + "SDFE_VerifyIK", + lib.SDFE_VerifyIK(sessionHandle, keyType, data, data.length, signature) + ); + return null; + }); + } + @Override public void eccExternalVerify(EccExternalVerifyRequest request) { EccExternalVerifyRequest req = requireRequest("request", request); @@ -1561,6 +1606,134 @@ public class JnaPcieCryptoService implements PcieCryptoService { }); } + @Override + public FirmwareInfoResult getFirmwareInfo() { + return sessionTemplate.withSession("SDFE_GetFirmwareInfo", (lib, deviceHandle, sessionHandle) -> { + SdfFirmwareInfo info = new SdfFirmwareInfo(); + sessionTemplate.ensureSuccess("SDFE_GetFirmwareInfo", lib.SDFE_GetFirmwareInfo(sessionHandle, info)); + info.read(); + + FirmwareInfoResult result = new FirmwareInfoResult(); + result.setBomInfo(Arrays.copyOf(info.bomInfo, info.bomInfo.length)); + result.setGd32Info(Arrays.copyOf(info.gd32Info, info.gd32Info.length)); + result.setN32s033Info(Arrays.copyOf(info.n32s033Info, info.n32s033Info.length)); + return result; + }); + } + + @Override + public void sdfeHashCopy() { + sessionTemplate.withTwoSessions("SDFE_HashCopy", (lib, deviceHandle, sessionFrom, sessionTo) -> { + sessionTemplate.ensureSuccess("SDFE_HashCopy", lib.SDFE_HashCopy(sessionTo, sessionFrom)); + return null; + }); + } + + @Override + public BackupDataResult sdfeEncrypt(SymmetricCryptoRequest request) { + SymmetricCryptoRequest req = requireRequest("request", request); + int algId = requireValidAlgId("algId", req.getAlgId()); + byte[] key = requireNonEmptyBytes("key", req.getKey()); + byte[] data = requireBytes("data", req.getData()); + int outBufferSize = requirePositive("outBufferSize", req.getOutBufferSize()); + byte[] iv = req.getIv(); + + try { + return sessionTemplate.withSession("SDFE_Encrypt", (lib, deviceHandle, sessionHandle) -> { + byte[] out = new byte[outBufferSize]; + IntByReference outLen = new IntByReference(out.length); + sessionTemplate.ensureSuccess( + "SDFE_Encrypt", + lib.SDFE_Encrypt(sessionHandle, key, key.length, algId, iv, data, data.length, out, outLen) + ); + return toBackupResult("SDFE_Encrypt", out, outLen.getValue()); + }); + } finally { + wipe(key); + } + } + + @Override + public BackupDataResult sdfeDecrypt(SymmetricCryptoRequest request) { + SymmetricCryptoRequest req = requireRequest("request", request); + int algId = requireValidAlgId("algId", req.getAlgId()); + byte[] key = requireNonEmptyBytes("key", req.getKey()); + byte[] data = requireBytes("data", req.getData()); + int outBufferSize = requirePositive("outBufferSize", req.getOutBufferSize()); + byte[] iv = req.getIv(); + + try { + return sessionTemplate.withSession("SDFE_Decrypt", (lib, deviceHandle, sessionHandle) -> { + byte[] out = new byte[outBufferSize]; + IntByReference outLen = new IntByReference(out.length); + sessionTemplate.ensureSuccess( + "SDFE_Decrypt", + lib.SDFE_Decrypt(sessionHandle, key, key.length, algId, iv, data, data.length, out, outLen) + ); + return toBackupResult("SDFE_Decrypt", out, outLen.getValue()); + }); + } finally { + wipe(key); + } + } + + @Override + public BackupDataResult sdfeHash(DigestRequest request) { + DigestRequest req = requireRequest("request", request); + int algId = requireValidAlgId("algId", req.getAlgId()); + byte[] data = requireBytes("data", req.getData()); + int outBufferSize = requirePositive("outBufferSize", req.getOutBufferSize()); + + return sessionTemplate.withSession("SDFE_Hash", (lib, deviceHandle, sessionHandle) -> { + byte[] out = new byte[outBufferSize]; + IntByReference outLen = new IntByReference(out.length); + sessionTemplate.ensureSuccess( + "SDFE_Hash", + lib.SDFE_Hash(sessionHandle, algId, data, data.length, out, outLen) + ); + return toBackupResult("SDFE_Hash", out, outLen.getValue()); + }); + } + + @Override + public BackupDataResult sdfeInternalEncryptEcc(EccInternalEncryptRequest request) { + EccInternalEncryptRequest req = requireRequest("request", request); + int keyIndex = requireNonNegative("keyIndex", req.getKeyIndex()); + byte[] data = requireBytes("data", req.getData()); + int outBufferSize = requirePositive("outBufferSize", req.getOutBufferSize()); + + return sessionTemplate.withSession("SDFE_InternalEncrypt_ECC", (lib, deviceHandle, sessionHandle) -> { + EccCipher cipher = new EccCipher(); + if (outBufferSize < cipher.size()) { + throw new IllegalArgumentException("outBufferSize must be >= " + cipher.size()); + } + sessionTemplate.ensureSuccess( + "SDFE_InternalEncrypt_ECC", + lib.SDFE_InternalEncrypt_ECC(sessionHandle, keyIndex, data, data.length, cipher) + ); + byte[] cipherBytes = toEccCipherBytes("SDFE_InternalEncrypt_ECC", cipher); + return toBackupResult("SDFE_InternalEncrypt_ECC", cipherBytes, cipherBytes.length); + }); + } + + @Override + public BackupDataResult sdfeInternalDecryptEcc(EccInternalDecryptRequest request) { + EccInternalDecryptRequest req = requireRequest("request", request); + int keyIndex = requireNonNegative("keyIndex", req.getKeyIndex()); + EccCipher cipher = toEccCipher("cipherBlob", req.getCipherBlob()); + int outBufferSize = requirePositive("outBufferSize", req.getOutBufferSize()); + + return sessionTemplate.withSession("SDFE_InternalDecrypt_ECC", (lib, deviceHandle, sessionHandle) -> { + byte[] out = new byte[outBufferSize]; + IntByReference outLen = new IntByReference(out.length); + sessionTemplate.ensureSuccess( + "SDFE_InternalDecrypt_ECC", + lib.SDFE_InternalDecrypt_ECC(sessionHandle, keyIndex, cipher, out, outLen) + ); + return toBackupResult("SDFE_InternalDecrypt_ECC", out, outLen.getValue()); + }); + } + @Override public HmacResult hmac(HmacRequest request) { HmacRequest req = requireRequest("request", request); @@ -1693,22 +1866,21 @@ public class JnaPcieCryptoService implements PcieCryptoService { public BackupDataResult backupIkComponent(int keyType) { int safeKeyType = requireNonNegative("keyType", keyType); - //todo 对接真实接口 - return sessionTemplate.withSession("SYD_IK_BackUp", (lib, deviceHandle, sessionHandle) -> { - SydIkComponent output = new SydIkComponent(); - sessionTemplate.ensureSuccess("SYD_IK_BackUp", lib.SYD_IK_BackUp(deviceHandle, safeKeyType, 1, output)); + return sessionTemplate.withSession("SDFE_BackupIK_EX", (lib, deviceHandle, sessionHandle) -> { + SdfeIkComponent output = new SdfeIkComponent(); + sessionTemplate.ensureSuccess("SDFE_BackupIK_EX", lib.SDFE_BackupIK_EX(sessionHandle, safeKeyType, output)); byte[] outputBytes = toBytes(output); - return toBackupResult("SYD_IK_BackUp", outputBytes, outputBytes.length); + return toBackupResult("SDFE_BackupIK_EX", outputBytes, outputBytes.length); }); } @Override public void recoverIkComponent(int keyType, byte[] ikComponent) { int safeKeyType = requireNonNegative("keyType", keyType); - SydIkComponent input = toSydIkComponent("ikComponent", ikComponent); + SdfeIkComponent input = toSdfeIkComponent("ikComponent", ikComponent); - sessionTemplate.withSession("SYD_IK_Recover", (lib, deviceHandle, sessionHandle) -> { - sessionTemplate.ensureSuccess("SYD_IK_Recover", lib.SYD_IK_Recover(deviceHandle, safeKeyType, 1, input)); + sessionTemplate.withSession("SDFE_RecoverIK_EX", (lib, deviceHandle, sessionHandle) -> { + sessionTemplate.ensureSuccess("SDFE_RecoverIK_EX", lib.SDFE_RecoverIK_EX(sessionHandle, safeKeyType, input)); return null; }); } @@ -2163,8 +2335,8 @@ public class JnaPcieCryptoService implements PcieCryptoService { return toStructure(name, value, new SdfeLmkComponent(), false); } - private static SydIkComponent toSydIkComponent(String name, byte[] value) { - return toStructure(name, value, new SydIkComponent(), false); + private static SdfeIkComponent toSdfeIkComponent(String name, byte[] value) { + return toStructure(name, value, new SdfeIkComponent(), false); } private static EnvelopedKeyBlob toEnvelopedKeyBlob(String name, byte[] value) { diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/service/MockPcieCryptoService.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/service/MockPcieCryptoService.java index 950a8ad..be3ac81 100644 --- a/src/main/java/com/cisd/tms/integration/crypto/pcie/service/MockPcieCryptoService.java +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/service/MockPcieCryptoService.java @@ -11,6 +11,8 @@ import com.cisd.tms.integration.crypto.pcie.model.DeviceCountResult; import com.cisd.tms.integration.crypto.pcie.model.DeviceInfoResult; import com.cisd.tms.integration.crypto.pcie.model.DeviceStatusResult; import com.cisd.tms.integration.crypto.pcie.model.DigestRequest; +import com.cisd.tms.integration.crypto.pcie.model.EccInternalDecryptRequest; +import com.cisd.tms.integration.crypto.pcie.model.EccInternalEncryptRequest; import com.cisd.tms.integration.crypto.pcie.model.EccExternalDecryptRequest; import com.cisd.tms.integration.crypto.pcie.model.EccExternalEncryptRequest; import com.cisd.tms.integration.crypto.pcie.model.EccExternalSignRequest; @@ -37,12 +39,14 @@ import com.cisd.tms.integration.crypto.pcie.model.GenerateKeyWithKekRequest; import com.cisd.tms.integration.crypto.pcie.model.GenerateKeyPairRequest; import com.cisd.tms.integration.crypto.pcie.model.HmacRequest; import com.cisd.tms.integration.crypto.pcie.model.HmacResult; +import com.cisd.tms.integration.crypto.pcie.model.FirmwareInfoResult; import com.cisd.tms.integration.crypto.pcie.model.ImportEncKeyPairEccRequest; -import com.cisd.tms.integration.crypto.pcie.model.ImportEncKeyPairRsaRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKekRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKeyWithIskEccRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKeyWithIskRsaRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKeyPairRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkSignRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest; import com.cisd.tms.integration.crypto.pcie.model.KekComponentRequest; import com.cisd.tms.integration.crypto.pcie.model.KeyStatusResult; import com.cisd.tms.integration.crypto.pcie.model.LoginStatusResult; @@ -297,15 +301,6 @@ public class MockPcieCryptoService implements PcieCryptoService { requireNonEmptyBytes("envelopedKeyBlob", req.getEnvelopedKeyBlob()); } - @Override - public void importEncryptedKeyPairRsa(ImportEncKeyPairRsaRequest request) { - ImportEncKeyPairRsaRequest req = requireRequest("request", request); - requireNonNegative("keyIndex", req.getKeyIndex()); - requirePositive("symAlgId", req.getSymAlgId()); - requireNonEmptyBytes("wrappedKey", req.getWrappedKey()); - requireNonEmptyBytes("encryptedData", req.getEncryptedData()); - } - @Override public BackupDataResult updateBackedKey(UpdateBackedKeyRequest request) { UpdateBackedKeyRequest req = requireRequest("request", request); @@ -342,6 +337,19 @@ public class MockPcieCryptoService implements PcieCryptoService { return mockBackup(size, 0x44); } + @Override + public BackupDataResult exportIkPublicKey(int keyType, int outBufferSize) { + requireNonNegative("keyType", keyType); + int size = requirePositive("outBufferSize", outBufferSize); + return mockBackup(size, 0x45); + } + + @Override + public BackupDataResult exportIkMac(int keyType) { + requireNonNegative("keyType", keyType); + return mockBackup(8, 0x46); + } + @Override public StandardKeyPairResult generateStandardRsaKeyPair(GenerateStandardRsaKeyPairRequest request) { GenerateStandardRsaKeyPairRequest req = requireRequest("request", request); @@ -540,6 +548,15 @@ public class MockPcieCryptoService implements PcieCryptoService { return mockBackup(size, 0x49); } + @Override + public BackupDataResult signIk(IkSignRequest request) { + IkSignRequest req = requireRequest("request", request); + requireNonNegative("keyType", req.getKeyType()); + requireBytes("data", req.getData()); + int size = requirePositive("signatureBufferSize", req.getSignatureBufferSize()); + return mockBackup(size, 0x5A); + } + @Override public BackupDataResult eccExternalSign(EccExternalSignRequest request) { EccExternalSignRequest req = requireRequest("request", request); @@ -558,6 +575,14 @@ public class MockPcieCryptoService implements PcieCryptoService { requireNonEmptyBytes("signature", req.getSignature()); } + @Override + public void verifyIk(IkVerifyRequest request) { + IkVerifyRequest req = requireRequest("request", request); + requireNonNegative("keyType", req.getKeyType()); + requireBytes("data", req.getData()); + requireNonEmptyBytes("signature", req.getSignature()); + } + @Override public void eccExternalVerify(EccExternalVerifyRequest request) { EccExternalVerifyRequest req = requireRequest("request", request); @@ -637,6 +662,67 @@ public class MockPcieCryptoService implements PcieCryptoService { return mockBackup(size, 0x77); } + @Override + public FirmwareInfoResult getFirmwareInfo() { + FirmwareInfoResult result = new FirmwareInfoResult(); + result.setBomInfo(new byte[5]); + result.setGd32Info(new byte[5]); + result.setN32s033Info(new byte[5]); + return result; + } + + @Override + public void sdfeHashCopy() { + // no-op + } + + @Override + public BackupDataResult sdfeEncrypt(SymmetricCryptoRequest request) { + SymmetricCryptoRequest req = requireRequest("request", request); + requirePositive("algId", req.getAlgId()); + requireNonEmptyBytes("key", req.getKey()); + requireBytes("data", req.getData()); + int size = requirePositive("outBufferSize", req.getOutBufferSize()); + return mockBackup(size, 0x72); + } + + @Override + public BackupDataResult sdfeDecrypt(SymmetricCryptoRequest request) { + SymmetricCryptoRequest req = requireRequest("request", request); + requirePositive("algId", req.getAlgId()); + requireNonEmptyBytes("key", req.getKey()); + requireBytes("data", req.getData()); + int size = requirePositive("outBufferSize", req.getOutBufferSize()); + return mockBackup(size, 0x73); + } + + @Override + public BackupDataResult sdfeHash(DigestRequest request) { + DigestRequest req = requireRequest("request", request); + requirePositive("algId", req.getAlgId()); + requireBytes("data", req.getData()); + int size = requirePositive("outBufferSize", req.getOutBufferSize()); + return mockBackup(size, 0x74); + } + + @Override + public BackupDataResult sdfeInternalEncryptEcc(EccInternalEncryptRequest request) { + EccInternalEncryptRequest req = requireRequest("request", request); + requireNonNegative("keyIndex", req.getKeyIndex()); + requireBytes("data", req.getData()); + int size = requirePositive("outBufferSize", req.getOutBufferSize()); + return mockBackup(size, 0x75); + } + + @Override + public BackupDataResult sdfeInternalDecryptEcc(EccInternalDecryptRequest request) { + EccInternalDecryptRequest req = requireRequest("request", request); + requireNonNegative("keyIndex", req.getKeyIndex()); + requireNonEmptyBytes("cipherBlob", req.getCipherBlob()); + int size = requirePositive("outBufferSize", req.getOutBufferSize()); + return mockBackup(size, 0x76); + } + @Override public HmacResult hmac(HmacRequest request) { HmacRequest req = requireRequest("request", request); @@ -710,7 +796,7 @@ public class MockPcieCryptoService implements PcieCryptoService { @Override public BackupDataResult backupIkComponent(int keyType) { requireNonNegative("keyType", keyType); - return mockBackup(new com.cisd.tms.integration.crypto.pcie.jna.SydIkComponent().size(), keyType); + return mockBackup(new com.cisd.tms.integration.crypto.pcie.jna.SdfeIkComponent().size(), keyType); } @Override diff --git a/src/main/java/com/cisd/tms/integration/crypto/pcie/service/PcieCryptoService.java b/src/main/java/com/cisd/tms/integration/crypto/pcie/service/PcieCryptoService.java index 44365c0..9fc1176 100644 --- a/src/main/java/com/cisd/tms/integration/crypto/pcie/service/PcieCryptoService.java +++ b/src/main/java/com/cisd/tms/integration/crypto/pcie/service/PcieCryptoService.java @@ -8,6 +8,8 @@ import com.cisd.tms.integration.crypto.pcie.model.DeviceCountResult; import com.cisd.tms.integration.crypto.pcie.model.DeviceInfoResult; import com.cisd.tms.integration.crypto.pcie.model.DeviceStatusResult; import com.cisd.tms.integration.crypto.pcie.model.DigestRequest; +import com.cisd.tms.integration.crypto.pcie.model.EccInternalDecryptRequest; +import com.cisd.tms.integration.crypto.pcie.model.EccInternalEncryptRequest; import com.cisd.tms.integration.crypto.pcie.model.EccExternalDecryptRequest; import com.cisd.tms.integration.crypto.pcie.model.EccExternalEncryptRequest; import com.cisd.tms.integration.crypto.pcie.model.EccExternalSignRequest; @@ -34,12 +36,14 @@ import com.cisd.tms.integration.crypto.pcie.model.GenerateKeyWithKekRequest; import com.cisd.tms.integration.crypto.pcie.model.GenerateKeyPairRequest; import com.cisd.tms.integration.crypto.pcie.model.HmacRequest; import com.cisd.tms.integration.crypto.pcie.model.HmacResult; +import com.cisd.tms.integration.crypto.pcie.model.FirmwareInfoResult; import com.cisd.tms.integration.crypto.pcie.model.ImportEncKeyPairEccRequest; -import com.cisd.tms.integration.crypto.pcie.model.ImportEncKeyPairRsaRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKekRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKeyWithIskEccRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKeyWithIskRsaRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKeyPairRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkSignRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest; import com.cisd.tms.integration.crypto.pcie.model.KekComponentRequest; import com.cisd.tms.integration.crypto.pcie.model.KeyStatusResult; import com.cisd.tms.integration.crypto.pcie.model.LoginStatusResult; @@ -59,199 +63,580 @@ import com.cisd.tms.integration.crypto.pcie.model.UkeyPinChangeRequest; import com.cisd.tms.integration.crypto.pcie.model.UkeyUnlockRequest; import com.cisd.tms.integration.crypto.pcie.model.UpdateBackedKeyRequest; +/** + * PCIe 密码卡强类型服务接口。 + * + *

该接口面向上层业务和控制器,屏蔽底层 JNA/native 指针细节, + * 统一暴露设备管理、密钥管理、算法运算、LMK/IK 生命周期、 + * UKey 操作以及文件管理等能力。

+ */ public interface PcieCryptoService { + + //----------------------------------------设备信息与初始化类接口----------------------------------------- + /** + * 查询当前环境可见的密码卡设备数量和正常设备数量。 + */ DeviceCountResult getDeviceCount(); + /** + * 读取密码卡配置信息快照。 + */ DeviceConfResult getDeviceConf(); + /** + * 读取密码卡基础设备信息。 + */ DeviceInfoResult getDeviceInfo(); + /** + * 生成指定长度的随机数。 + * + * @param length 随机数字节长度 + */ byte[] generateRandom(int length); + /** + * 执行密码卡初始化识别流程,通常用于设置或切换初始化 PIN。 + * + * @param oldPin 旧 PIN + * @param newPin 新 PIN + */ void initIdentify(byte[] oldPin, byte[] newPin); + /** + * 初始化主密钥体系,通常包含 LMK、IK 和用户密钥初始化。 + * + * @param oldPin 旧 PIN + * @param newPin 新 PIN + * @return LMK seed MAC + */ byte[] initializeMasterKey(byte[] oldPin, byte[] newPin); + /** + * 触发设备自检。 + */ void deviceSelfTest(); + /** + * 获取设备运行状态详情。 + */ DeviceStatusResult getDeviceStatus(); + /** + * 执行设备恢复出厂设置。 + */ void deviceFactoryReset(); + + //----------------------------------------私钥访问控制类接口------------------------------------------ + /** + * 修改指定私钥索引的访问口令。 + */ void changePrivateKeyAccessPassword(ChangePrivateKeyPasswordRequest request); + /** + * 获取指定私钥索引的访问权限。 + */ void getPrivateKeyAccessRight(PrivateKeyAccessRequest request); + /** + * 释放指定私钥索引的访问权限。 + */ void releasePrivateKeyAccessRight(int keyIndex); + //----------------------------------------用户密钥与 KEK 管理类接口------------------------------------------ + /** + * 在设备内部生成 ECC 用户密钥对。 + */ void generateKeyPairEcc(GenerateKeyPairRequest request); + /** + * 在设备内部生成 RSA 用户密钥对。 + */ void generateKeyPairRsa(GenerateKeyPairRequest request); + /** + * 导入 ECC 用户密钥对。 + */ void importKeyPairEcc(ImportKeyPairRequest request); + /** + * 导入 RSA 用户密钥对。 + */ void importKeyPairRsa(ImportKeyPairRequest request); + /** + * 生成 KEK。 + */ void generateKek(GenerateKekRequest request); + /** + * 导入 KEK 明文。 + */ void importKek(ImportKekRequest request); + /** + * 导入 KEK 分量。 + */ void importKekComponent(KekComponentRequest request); + /** + * 导出 KEK 分量。 + */ BackupDataResult exportKekComponent(ExportKekComponentRequest request); + /** + * 备份指定用户密钥。 + */ BackupDataResult backupUserKey(int keyIndex, int keyType, int outBufferSize); + /** + * 恢复指定用户密钥。 + */ void recoverUserKey(RecoverUserKeyRequest request); + /** + * 备份指定 KEK。 + */ BackupDataResult backupKek(int keyIndex, int outBufferSize); + /** + * 恢复指定 KEK。 + */ void recoverKek(RecoverKekRequest request); + /** + * 删除指定用户密钥。 + */ void deleteUserKey(int keyIndex); + /** + * 删除指定 KEK。 + */ void deleteKek(int keyIndex); + /** + * 备份整卡全部密钥数据。 + */ BackupDataResult backupAllKey(int outBufferSize); + /** + * 使用整卡备份数据恢复全部密钥。 + */ void restoreAllKey(byte[] keyImage); + /** + * 查询 ECC 用户密钥状态。 + */ KeyStatusResult statusUserKeyEcc(int keyIndex, int keyType); + /** + * 查询 RSA 用户密钥状态。 + */ KeyStatusResult statusUserKeyRsa(int keyIndex, int keyType); + /** + * 查询 KEK 状态。 + */ KeyStatusResult statusKek(int keyIndex); + /** + * 导入加密封装的 ECC 密钥对。 + */ void importEncryptedKeyPairEcc(ImportEncKeyPairEccRequest request); - void importEncryptedKeyPairRsa(ImportEncKeyPairRsaRequest request); - + /** + * 更新旧备份数据,返回新备份数据。 + */ BackupDataResult updateBackedKey(UpdateBackedKeyRequest request); + + //----------------------------------------公钥导出与标准密钥对类接口------------------------------------------ + /** + * 导出 RSA 签名公钥。 + */ BackupDataResult exportSignPublicKeyRsa(int keyIndex, int outBufferSize); + /** + * 导出 RSA 加密公钥。 + */ BackupDataResult exportEncPublicKeyRsa(int keyIndex, int outBufferSize); + /** + * 导出 ECC 签名公钥。 + */ BackupDataResult exportSignPublicKeyEcc(int keyIndex, int outBufferSize); + /** + * 导出 ECC 加密公钥。 + */ BackupDataResult exportEncPublicKeyEcc(int keyIndex, int outBufferSize); + /** + * 生成标准 RSA 密钥对并导出结果。 + */ StandardKeyPairResult generateStandardRsaKeyPair(GenerateStandardRsaKeyPairRequest request); + /** + * 生成标准 ECC 密钥对并导出结果。 + */ StandardKeyPairResult generateStandardEccKeyPair(GenerateStandardEccKeyPairRequest request); + //----------------------------------------会话密钥与数字信封类接口------------------------------------------ + + /** + * 使用指定 KEK 生成会话密钥并导出包裹结果。 + */ BackupDataResult generateKeyWithKek(GenerateKeyWithKekRequest request); + /** + * 执行 RSA 外部公钥运算。 + */ BackupDataResult rsaExternalPublicKeyOperation(RsaExternalPublicKeyOpRequest request); + /** + * 执行 RSA 外部私钥运算。 + */ BackupDataResult rsaExternalPrivateKeyOperation(RsaExternalPrivateKeyOpRequest request); + /** + * 执行 RSA 内部公钥运算。 + */ BackupDataResult rsaInternalPublicKeyOperation(RsaInternalKeyOpRequest request); + /** + * 执行 RSA 内部私钥运算。 + */ BackupDataResult rsaInternalPrivateKeyOperation(RsaInternalKeyOpRequest request); + /** + * 使用内部 RSA 公钥生成会话密钥。 + */ BackupDataResult generateKeyWithIpkRsa(GenerateKeyWithIpkRsaRequest request); + /** + * 使用外部 RSA 公钥生成会话密钥。 + */ BackupDataResult generateKeyWithEpkRsa(GenerateKeyWithEpkRsaRequest request); + /** + * 使用内部 RSA 私钥导入会话密钥。 + */ void importKeyWithIskRsa(ImportKeyWithIskRsaRequest request); + /** + * 使用内部 ECC 公钥生成会话密钥。 + */ BackupDataResult generateKeyWithIpkEcc(GenerateKeyWithIpkEccRequest request); + /** + * 使用外部 ECC 公钥生成会话密钥。 + */ BackupDataResult generateKeyWithEpkEcc(GenerateKeyWithEpkEccRequest request); + /** + * 使用内部 ECC 私钥导入会话密钥。 + */ void importKeyWithIskEcc(ImportKeyWithIskEccRequest request); + /** + * 执行基于 RSA 的数字信封交换。 + */ BackupDataResult exchangeDigitEnvelopeBaseOnRsa(ExchangeDigitEnvelopeRsaRequest request); + /** + * 执行基于 ECC 的数字信封交换。 + */ BackupDataResult exchangeDigitEnvelopeBaseOnEcc(ExchangeDigitEnvelopeEccRequest request); + /** + * 生成 ECC 协商所需公钥材料并返回会话密钥。 + */ AgreementDataAndKeyEccResult generateAgreementDataAndKeyWithEcc(GenerateAgreementDataAndKeyEccRequest request); + /** + * 基于既有 ECC 协商材料生成会话密钥。 + */ EccAgreementSessionKeyResult generateSessionKeyWithEccAgreement(EccAgreementSessionKeyRequest request); + + //----------------------------------------SDF通用算法运算类接口------------------------------------------ + /** + * 使用通用内部 ECC 密钥执行签名。 + */ BackupDataResult eccInternalSign(EccInternalSignRequest request); + /** + * 使用外部 ECC 私钥执行签名。 + */ BackupDataResult eccExternalSign(EccExternalSignRequest request); + /** + * 使用通用内部 ECC 密钥执行验签。 + */ void eccInternalVerify(EccInternalVerifyRequest request); + /** + * 使用外部 ECC 公钥执行验签。 + */ void eccExternalVerify(EccExternalVerifyRequest request); + /** + * 使用外部 ECC 公钥执行加密。 + */ BackupDataResult eccExternalEncrypt(EccExternalEncryptRequest request); + /** + * 使用外部 ECC 私钥执行解密。 + */ BackupDataResult eccExternalDecrypt(EccExternalDecryptRequest request); + /** + * 使用明文对称密钥执行加密。 + */ BackupDataResult encryptWithPlainKey(SymmetricCryptoRequest request); + /** + * 使用明文对称密钥执行解密。 + */ BackupDataResult decryptWithPlainKey(SymmetricCryptoRequest request); + /** + * 使用 KEK 包裹密钥执行加密。 + */ BackupDataResult encryptWithKekWrappedKey(SymmetricKekCryptoRequest request); + /** + * 使用 KEK 包裹密钥执行解密。 + */ BackupDataResult decryptWithKekWrappedKey(SymmetricKekCryptoRequest request); + /** + * 使用明文对称密钥计算 MAC。 + */ BackupDataResult calculateMacWithPlainKey(MacCalcRequest request); + /** + * 使用通用 SDF 摘要流程计算杂凑。 + */ BackupDataResult digest(DigestRequest request); + + //----------------------------------------SD FE 专用算法扩展接口------------------------------------------ + + /** + * 读取固件版本信息。 + */ + FirmwareInfoResult getFirmwareInfo(); + + /** + * 复制两个会话之间的 SD FE Hash 状态。 + */ + void sdfeHashCopy(); + + /** + * 使用 SD FE 明文对称密钥接口执行加密。 + */ + BackupDataResult sdfeEncrypt(SymmetricCryptoRequest request); + + /** + * 使用 SD FE 明文对称密钥接口执行解密。 + */ + BackupDataResult sdfeDecrypt(SymmetricCryptoRequest request); + + /** + * 使用 SD FE 单包摘要接口执行杂凑。 + */ + BackupDataResult sdfeHash(DigestRequest request); + + /** + * 使用内部 ECC 用户密钥执行加密。 + */ + BackupDataResult sdfeInternalEncryptEcc(EccInternalEncryptRequest request); + + /** + * 使用内部 ECC 用户密钥执行解密。 + */ + BackupDataResult sdfeInternalDecryptEcc(EccInternalDecryptRequest request); + + /** + * 使用 SD FE HMAC 流程计算 HMAC。 + */ HmacResult hmac(HmacRequest request); + + //----------------------------------------LMK 生命周期类接口------------------------------------------ + /** + * 生成 LMK。 + */ void generateLmk(); + /** + * 加载 LMK。 + */ void loadLmk(); + /** + * 备份 LMK。 + */ void backupLmk(); + /** + * 恢复 LMK。 + */ void recoverLmk(); + /** + * 销毁 LMK。 + */ void destroyLmk(); + /** + * 检查 LMK 是否存在且可用。 + */ boolean checkLmk(); + /** + * 导出 LMK seed MAC。 + */ byte[] exportLmkSeedMac(); + /** + * 导出 LMK 分量扩展备份数据。 + */ BackupDataResult backupLmkEx(); + /** + * 使用扩展备份数据恢复 LMK。 + */ void recoverLmkEx(byte[] lmkComponent); + + //----------------------------------------IK 生命周期类接口。------------------------------------------ + /** + * 生成 IK。 + */ void generateIk(int keyType); + /** + * 导出 IK 公钥。 + */ + BackupDataResult exportIkPublicKey(int keyType, int outBufferSize); + + /** + * 导出 IK 校验值。 + */ + BackupDataResult exportIkMac(int keyType); + + /** + * 使用 IK 执行专用签名。 + */ + BackupDataResult signIk(IkSignRequest request); + + /** + * 使用 IK 执行专用验签。 + */ + void verifyIk(IkVerifyRequest request); + + /** + * 导出 IK 分量扩展备份数据。 + */ BackupDataResult backupIkComponent(int keyType); + /** + * 使用扩展备份数据恢复 IK。 + */ void recoverIkComponent(int keyType, byte[] ikComponent); + /** + * 触发 IK 设备内备份。 + */ void backupIk(int keyType); + /** + * 触发 IK 设备内恢复。 + */ void recoverIk(int keyType); + /** + * 销毁 IK。 + */ void destroyIk(int keyType); + /** + * 查询 IK 状态。 + */ KeyStatusResult statusIk(int keyType); + + //----------------------------------------UKey 管理类接口------------------------------------------- + + /** + * 生成 UKey 管理员。 + */ void generateUkey(UkeyGenerateRequest request); + /** + * 登录 UKey。 + */ void loginUkey(UkeyLoginRequest request); + /** + * 修改 UKey PIN。 + */ void changeUkeyPin(UkeyPinChangeRequest request); + /** + * 解锁 UKey。 + */ void unlockUkey(UkeyUnlockRequest request); + /** + * 从 UKey 读取 LMK 分量到设备运行态。 + */ void readLmkComponent(byte[] ukeyPin); + /** + * 从 UKey 读取 IK 分量到设备运行态。 + */ void readUkeyIkComponent(int keyType, byte[] ukeyPin); + /** + * 为 UKey 生成证书。 + */ void generateCertificate(byte[] ukeyPin); + /** + * 注销指定管理员索引的 UKey 登录态。 + */ void logoutAdmin(int adminIndex); + /** + * 查询 UKey 登录状态。 + */ LoginStatusResult loginStatus(); + /** + * 设备文件系统类接口。 + */ + /** + * 在设备文件系统中创建文件。 + */ void createFile(FileCreateRequest request); + /** + * 向设备文件系统写入文件内容。 + */ void writeFile(FileWriteRequest request); + /** + * 从设备文件系统读取文件内容。 + */ BackupDataResult readFile(FileReadRequest request); + /** + * 删除设备文件系统中的文件。 + */ void deleteFile(String fileName); } diff --git a/src/main/java/com/cisd/tms/modules/device/controller/CryptoCardController.java b/src/main/java/com/cisd/tms/modules/device/controller/CryptoCardController.java index 54de185..fa2cdf9 100644 --- a/src/main/java/com/cisd/tms/modules/device/controller/CryptoCardController.java +++ b/src/main/java/com/cisd/tms/modules/device/controller/CryptoCardController.java @@ -598,15 +598,6 @@ public class CryptoCardController { return ApiResponse.success(); } - @PostMapping("/keypair/rsa/import-encrypted") - @Operation(summary = "导入加密 RSA 密钥对", description = "导入包裹密钥保护的 RSA 密钥对数据。") - public ApiResponse importEncryptedKeyPairRsa( - @Valid @RequestBody CryptoImportEncryptedKeyPairRsaInternalRequest request - ) { - pcieCryptoService.importEncryptedKeyPairRsa(toImportEncryptedKeyPairRsaRequest(request)); - return ApiResponse.success(); - } - @PostMapping("/keys/update-backed") @Operation(summary = "更新备份数据", description = "更新旧备份结构并返回新的备份数据 HEX。") public ApiResponse> updateBackedKey( diff --git a/src/main/java/com/cisd/tms/modules/device/dto/crypto/request/CryptoImportEncryptedKeyPairRsaInternalRequest.java b/src/main/java/com/cisd/tms/modules/device/dto/crypto/request/CryptoImportEncryptedKeyPairRsaInternalRequest.java deleted file mode 100644 index b38aa4f..0000000 --- a/src/main/java/com/cisd/tms/modules/device/dto/crypto/request/CryptoImportEncryptedKeyPairRsaInternalRequest.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.cisd.tms.modules.device.dto.crypto.request; - -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.NotBlank; - -public class CryptoImportEncryptedKeyPairRsaInternalRequest { - - @Min(0) - private int keyIndex; - - @Min(1) - private int symAlgId; - - @NotBlank - private String wrappedKeyBase64; - - @NotBlank - private String encryptedDataBase64; - - public int getKeyIndex() { - return keyIndex; - } - - public void setKeyIndex(int keyIndex) { - this.keyIndex = keyIndex; - } - - public int getSymAlgId() { - return symAlgId; - } - - public void setSymAlgId(int symAlgId) { - this.symAlgId = symAlgId; - } - - public String getWrappedKeyBase64() { - return wrappedKeyBase64; - } - - public void setWrappedKeyBase64(String wrappedKeyBase64) { - this.wrappedKeyBase64 = wrappedKeyBase64; - } - - public String getEncryptedDataBase64() { - return encryptedDataBase64; - } - - public void setEncryptedDataBase64(String encryptedDataBase64) { - this.encryptedDataBase64 = encryptedDataBase64; - } -} diff --git a/src/main/java/com/cisd/tms/modules/device/support/crypto/CryptoRequestMapper.java b/src/main/java/com/cisd/tms/modules/device/support/crypto/CryptoRequestMapper.java index 65a3bc0..295162b 100644 --- a/src/main/java/com/cisd/tms/modules/device/support/crypto/CryptoRequestMapper.java +++ b/src/main/java/com/cisd/tms/modules/device/support/crypto/CryptoRequestMapper.java @@ -3,7 +3,6 @@ package com.cisd.tms.modules.device.support.crypto; import com.cisd.tms.integration.crypto.pcie.model.ChangePrivateKeyPasswordRequest; import com.cisd.tms.integration.crypto.pcie.model.GenerateKeyPairRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportEncKeyPairEccRequest; -import com.cisd.tms.integration.crypto.pcie.model.ImportEncKeyPairRsaRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKekRequest; import com.cisd.tms.integration.crypto.pcie.model.ImportKeyPairRequest; import com.cisd.tms.integration.crypto.pcie.model.KekComponentRequest; @@ -20,7 +19,6 @@ import com.cisd.tms.integration.crypto.pcie.model.UpdateBackedKeyRequest; import com.cisd.tms.modules.device.dto.crypto.request.CryptoChangePrivateKeyPasswordInternalRequest; import com.cisd.tms.modules.device.dto.crypto.request.CryptoGenerateKeyPairInternalRequest; import com.cisd.tms.modules.device.dto.crypto.request.CryptoImportEncryptedKeyPairEccInternalRequest; -import com.cisd.tms.modules.device.dto.crypto.request.CryptoImportEncryptedKeyPairRsaInternalRequest; import com.cisd.tms.modules.device.dto.crypto.request.CryptoImportKekInternalRequest; import com.cisd.tms.modules.device.dto.crypto.request.CryptoImportKeyPairInternalRequest; import com.cisd.tms.modules.device.dto.crypto.request.CryptoKekComponentImportInternalRequest; @@ -131,15 +129,6 @@ public final class CryptoRequestMapper { return req; } - public static ImportEncKeyPairRsaRequest toImportEncryptedKeyPairRsaRequest(CryptoImportEncryptedKeyPairRsaInternalRequest request) { - ImportEncKeyPairRsaRequest req = new ImportEncKeyPairRsaRequest(); - req.setKeyIndex(request.getKeyIndex()); - req.setSymAlgId(request.getSymAlgId()); - req.setWrappedKey(CryptoPayloadCodec.decodeBase64(request.getWrappedKeyBase64())); - req.setEncryptedData(CryptoPayloadCodec.decodeBase64(request.getEncryptedDataBase64())); - return req; - } - public static UpdateBackedKeyRequest toUpdateBackedKeyRequest(CryptoUpdateBackedKeyInternalRequest request) { UpdateBackedKeyRequest req = new UpdateBackedKeyRequest(); req.setOldData(CryptoPayloadCodec.decodeBase64(request.getOldDataBase64())); diff --git a/src/main/java/com/cisd/tms/modules/mk/controller/LmkController.java b/src/main/java/com/cisd/tms/modules/mk/controller/LmkController.java index 42e20a9..e6e90e1 100644 --- a/src/main/java/com/cisd/tms/modules/mk/controller/LmkController.java +++ b/src/main/java/com/cisd/tms/modules/mk/controller/LmkController.java @@ -35,6 +35,7 @@ public class LmkController { @PostMapping("/masterKey/destroy") @Operation(summary = "销毁主密钥", description = "销毁当前密码卡中的主密钥,失败直接抛出异常。") public ApiResponse destroyMasterKey() { + //销毁主密钥、内部密钥、用户密钥 lmkService.destroyMasterKey(); return ApiResponse.success(); } diff --git a/src/main/java/com/cisd/tms/modules/mk/dto/MasterKeyPacketIkPart.java b/src/main/java/com/cisd/tms/modules/mk/dto/MasterKeyPacketIkPart.java index bf6002c..512454b 100644 --- a/src/main/java/com/cisd/tms/modules/mk/dto/MasterKeyPacketIkPart.java +++ b/src/main/java/com/cisd/tms/modules/mk/dto/MasterKeyPacketIkPart.java @@ -5,14 +5,22 @@ public class MasterKeyPacketIkPart { private int keyType; private String mac; private String component; + private String publicKey; + private String publicKeyMac; public MasterKeyPacketIkPart() { } public MasterKeyPacketIkPart(int keyType, String mac, String component) { + this(keyType, mac, component, null, null); + } + + public MasterKeyPacketIkPart(int keyType, String mac, String component, String publicKey, String publicKeyMac) { this.keyType = keyType; this.mac = mac; this.component = component; + this.publicKey = publicKey; + this.publicKeyMac = publicKeyMac; } public int getKeyType() { @@ -38,4 +46,20 @@ public class MasterKeyPacketIkPart { public void setComponent(String component) { this.component = component; } + + public String getPublicKey() { + return publicKey; + } + + public void setPublicKey(String publicKey) { + this.publicKey = publicKey; + } + + public String getPublicKeyMac() { + return publicKeyMac; + } + + public void setPublicKeyMac(String publicKeyMac) { + this.publicKeyMac = publicKeyMac; + } } diff --git a/src/main/java/com/cisd/tms/modules/mk/service/impl/LmkServiceImpl.java b/src/main/java/com/cisd/tms/modules/mk/service/impl/LmkServiceImpl.java index a50fa6b..08ba671 100644 --- a/src/main/java/com/cisd/tms/modules/mk/service/impl/LmkServiceImpl.java +++ b/src/main/java/com/cisd/tms/modules/mk/service/impl/LmkServiceImpl.java @@ -6,8 +6,8 @@ import com.cisd.tms.integration.crypto.pcie.jna.EccRefPublicKey; import com.cisd.tms.integration.crypto.pcie.jna.EccSignature; import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult; import com.cisd.tms.integration.crypto.pcie.model.DigestRequest; -import com.cisd.tms.integration.crypto.pcie.model.EccInternalSignRequest; -import com.cisd.tms.integration.crypto.pcie.model.EccInternalVerifyRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkSignRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest; import com.cisd.tms.integration.crypto.pcie.model.RecoverUserKeyRequest; import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService; import com.cisd.tms.modules.mk.common.LMKConstant; @@ -45,6 +45,10 @@ public class LmkServiceImpl implements LmkService { private static final int LMK_MAC_BYTE_LENGTH = 8; private static final int IK_COMPONENT_MAC_BYTE_LENGTH = 8; private static final int IK_COMPONENT_DATA_LENGTH = 3 * 64; + private static final int IK_PUBLIC_KEY_BYTE_LENGTH = new EccRefPublicKey().size(); + private static final int IK_PUBLIC_KEY_MAC_BYTE_LENGTH = 8; + private static final int IK_COMPONENT_TOTAL_BYTE_LENGTH = + IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH + IK_PUBLIC_KEY_BYTE_LENGTH + IK_PUBLIC_KEY_MAC_BYTE_LENGTH; private static final int USER_KEY_INDEX = 1; private static final int USER_KEY_TYPE_SIGN = 0; private static final int USER_KEY_TYPE_ENC = 1; @@ -83,29 +87,29 @@ public class LmkServiceImpl implements LmkService { @Override public String exportIkPublicKeyHex() { int outBufferSize = new EccRefPublicKey().size(); - BackupDataResult result = pcieCryptoService.exportSignPublicKeyEcc(AUTH_SIGN_KEY_INDEX, outBufferSize); + BackupDataResult result = pcieCryptoService.exportIkPublicKey(AUTH_SIGN_KEY_INDEX, outBufferSize); return Hex.toHexString(result.getData()); } @Override public String signIk(String rawData) { byte[] digest = digestForInternalSign(rawData); - EccInternalSignRequest request = new EccInternalSignRequest(); - request.setKeyIndex(AUTH_SIGN_KEY_INDEX); + IkSignRequest request = new IkSignRequest(); + request.setKeyType(AUTH_SIGN_KEY_INDEX); request.setData(digest); request.setSignatureBufferSize(new EccSignature().size()); - BackupDataResult result = pcieCryptoService.eccInternalSign(request); + BackupDataResult result = pcieCryptoService.signIk(request); return Hex.toHexString(result.getData()); } @Override public void verifyIk(String rawData, String signatureHex) { byte[] digest = digestForInternalSign(rawData); - EccInternalVerifyRequest request = new EccInternalVerifyRequest(); - request.setKeyIndex(AUTH_SIGN_KEY_INDEX); + IkVerifyRequest request = new IkVerifyRequest(); + request.setKeyType(AUTH_SIGN_KEY_INDEX); request.setData(digest); request.setSignature(Hex.decode(signatureHex)); - pcieCryptoService.eccInternalVerify(request); + pcieCryptoService.verifyIk(request); } @Override @@ -124,12 +128,16 @@ public class LmkServiceImpl implements LmkService { packet.setIkAuth(new MasterKeyPacketIkPart( IKEnums.KEY_TYPE_AUTH.getCode(), authIkBackup.macHex(), - requiredComponent(authIkBackup.componentMap(), index, "ikAuth") + requiredComponent(authIkBackup.componentMap(), index, "ikAuth"), + authIkBackup.publicKeyHex(), + authIkBackup.publicKeyMacHex() )); packet.setIkDevice(new MasterKeyPacketIkPart( IKEnums.KEY_TYPE_DEVICE.getCode(), deviceIkBackup.macHex(), - requiredComponent(deviceIkBackup.componentMap(), index, "ikDevice") + requiredComponent(deviceIkBackup.componentMap(), index, "ikDevice"), + deviceIkBackup.publicKeyHex(), + deviceIkBackup.publicKeyMacHex() )); packet.setUserKeys(List.of( buildUserKeyPacket(USER_KEY_INDEX, USER_KEY_TYPE_SIGN, index), @@ -215,6 +223,8 @@ public class LmkServiceImpl implements LmkService { private String composeIkHex(List packets, boolean authKey) { int keyType = authKey ? IKEnums.KEY_TYPE_AUTH.getCode() : IKEnums.KEY_TYPE_DEVICE.getCode(); String mac = requireConsistentIkMac(packets, keyType); + String publicKey = requireConsistentIkPublicKey(packets, keyType); + String publicKeyMac = requireConsistentIkPublicKeyMac(packets, keyType); StringBuilder builder = new StringBuilder(); for (MasterKeyBackupPacket packet : packets) { MasterKeyPacketIkPart part = authKey ? packet.getIkAuth() : packet.getIkDevice(); @@ -223,7 +233,7 @@ public class LmkServiceImpl implements LmkService { } builder.append(part.getComponent()); } - builder.append(mac); + builder.append(mac).append(publicKey).append(publicKeyMac); return builder.toString(); } @@ -263,17 +273,27 @@ public class LmkServiceImpl implements LmkService { private ParsedIkBackup parseIkBackupMaterial(int keyType) { BackupDataResult backupData = pcieCryptoService.backupIkComponent(keyType); byte[] normalized = normalizeBackupData(backupData); - if (normalized.length < IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH) { + if (normalized.length < IK_COMPONENT_TOTAL_BYTE_LENGTH) { throw new IllegalStateException("backup ik data length is too short: " + normalized.length); } byte[] componentBytes = Arrays.copyOfRange(normalized, 0, IK_COMPONENT_DATA_LENGTH); byte[] mac = Arrays.copyOfRange(normalized, IK_COMPONENT_DATA_LENGTH, IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH); + byte[] publicKey = Arrays.copyOfRange( + normalized, + IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH, + IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH + IK_PUBLIC_KEY_BYTE_LENGTH + ); + byte[] publicKeyMac = Arrays.copyOfRange( + normalized, + IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH + IK_PUBLIC_KEY_BYTE_LENGTH, + IK_COMPONENT_DATA_LENGTH + IK_COMPONENT_MAC_BYTE_LENGTH + IK_PUBLIC_KEY_BYTE_LENGTH + IK_PUBLIC_KEY_MAC_BYTE_LENGTH + ); String[] splitComponents = DivisionUtils.equalDivision(Hex.toHexString(componentBytes), LMKConstant.COMPONENT_NUM); Map componentMap = new HashMap<>(); for (int i = 0; i < LMKConstant.COMPONENT_NUM; i++) { componentMap.put(LMKConstant.KEY_ORDER[i], splitComponents[i]); } - return new ParsedIkBackup(Hex.toHexString(mac), componentMap); + return new ParsedIkBackup(Hex.toHexString(mac), componentMap, Hex.toHexString(publicKey), Hex.toHexString(publicKeyMac)); } private MasterKeyPacketUserKeyPart buildUserKeyPacket(int keyIndex, int keyType, int componentIndex) { @@ -365,6 +385,42 @@ public class LmkServiceImpl implements LmkService { return mac; } + private String requireConsistentIkPublicKey(List packets, int keyType) { + String publicKey = null; + for (MasterKeyBackupPacket packet : packets) { + MasterKeyPacketIkPart part = keyType == IKEnums.KEY_TYPE_AUTH.getCode() ? packet.getIkAuth() : packet.getIkDevice(); + if (part == null || part.getPublicKey() == null || part.getPublicKey().isBlank()) { + throw new IllegalArgumentException("ik publicKey missing"); + } + if (publicKey == null) { + publicKey = part.getPublicKey(); + continue; + } + if (!publicKey.equals(part.getPublicKey())) { + throw new IllegalArgumentException("ik publicKey is inconsistent"); + } + } + return publicKey; + } + + private String requireConsistentIkPublicKeyMac(List packets, int keyType) { + String publicKeyMac = null; + for (MasterKeyBackupPacket packet : packets) { + MasterKeyPacketIkPart part = keyType == IKEnums.KEY_TYPE_AUTH.getCode() ? packet.getIkAuth() : packet.getIkDevice(); + if (part == null || part.getPublicKeyMac() == null || part.getPublicKeyMac().isBlank()) { + throw new IllegalArgumentException("ik publicKeyMac missing"); + } + if (publicKeyMac == null) { + publicKeyMac = part.getPublicKeyMac(); + continue; + } + if (!publicKeyMac.equals(part.getPublicKeyMac())) { + throw new IllegalArgumentException("ik publicKeyMac is inconsistent"); + } + } + return publicKeyMac; + } + private MasterKeyPacketUserKeyPart findUserKeyPart(MasterKeyBackupPacket packet, int keyIndex, int keyType) { return packet.getUserKeys().stream() .filter(item -> item.getKeyIndex() == keyIndex && item.getKeyType() == keyType) @@ -390,6 +446,6 @@ public class LmkServiceImpl implements LmkService { private record ParsedMasterKeyBackup(String lmkMacHex, Map componentMap) { } - private record ParsedIkBackup(String macHex, Map componentMap) { + private record ParsedIkBackup(String macHex, Map componentMap, String publicKeyHex, String publicKeyMacHex) { } } diff --git a/src/test/java/com/cisd/tms/integration/crypto/pcie/service/JnaPcieCryptoServiceTest.java b/src/test/java/com/cisd/tms/integration/crypto/pcie/service/JnaPcieCryptoServiceTest.java index 6a45036..9c42d44 100644 --- a/src/test/java/com/cisd/tms/integration/crypto/pcie/service/JnaPcieCryptoServiceTest.java +++ b/src/test/java/com/cisd/tms/integration/crypto/pcie/service/JnaPcieCryptoServiceTest.java @@ -2,8 +2,22 @@ package com.cisd.tms.integration.crypto.pcie.service; import com.cisd.tms.integration.crypto.config.CryptoCardProperties; import com.cisd.tms.integration.crypto.pcie.PcieSessionTemplate; +import com.cisd.tms.integration.crypto.pcie.jna.EccCipher; +import com.cisd.tms.integration.crypto.pcie.jna.EccRefPublicKey; +import com.cisd.tms.integration.crypto.pcie.jna.EccSignature; import com.cisd.tms.integration.crypto.pcie.jna.PcieNativeLibrary; +import com.cisd.tms.integration.crypto.pcie.jna.SdfFirmwareInfo; +import com.cisd.tms.integration.crypto.pcie.jna.SdfeIkComponent; +import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult; +import com.cisd.tms.integration.crypto.pcie.model.DigestRequest; +import com.cisd.tms.integration.crypto.pcie.model.EccInternalDecryptRequest; +import com.cisd.tms.integration.crypto.pcie.model.EccInternalEncryptRequest; +import com.cisd.tms.integration.crypto.pcie.model.FirmwareInfoResult; +import com.cisd.tms.integration.crypto.pcie.model.IkSignRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest; +import com.cisd.tms.integration.crypto.pcie.model.SymmetricCryptoRequest; import com.sun.jna.Pointer; +import com.sun.jna.ptr.IntByReference; import java.nio.charset.StandardCharsets; import java.util.Arrays; import org.junit.jupiter.api.Assertions; @@ -47,4 +61,399 @@ class JnaPcieCryptoServiceTest { Assertions.assertArrayEquals(new byte[] {0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF}, mac); Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_InitializeMasterKey"), Mockito.any()); } + + @Test + void shouldBackupIkComponentViaSdfeBackupIkEx() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_BackupIK_EX"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_BackupIK_EX(Mockito.any(), Mockito.eq(2), Mockito.any(SdfeIkComponent.class))) + .thenAnswer(call -> { + SdfeIkComponent output = call.getArgument(2); + Arrays.fill(output.component, (byte) 0x11); + Arrays.fill(output.priMac, (byte) 0x22); + output.pubkey.bits = 256; + Arrays.fill(output.pubkey.x, (byte) 0x33); + Arrays.fill(output.pubkey.y, (byte) 0x44); + Arrays.fill(output.pubMac, (byte) 0x55); + return 0; + }); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + byte[] data = service.backupIkComponent(2).getData(); + + Assertions.assertEquals(new SdfeIkComponent().size(), data.length); + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_BackupIK_EX"), Mockito.any()); + } + + @Test + void shouldRecoverIkComponentViaSdfeRecoverIkEx() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + byte[] ikComponent = new byte[new SdfeIkComponent().size()]; + Arrays.fill(ikComponent, (byte) 0x5A); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_RecoverIK_EX"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_RecoverIK_EX(Mockito.any(), Mockito.eq(1), Mockito.any(SdfeIkComponent.class))) + .thenReturn(0); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + service.recoverIkComponent(1, ikComponent); + + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_RecoverIK_EX"), Mockito.any()); + } + + @Test + void shouldExportIkPublicKeyViaSdfeExportIkPublicKey() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_ExportIKPublicKey"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_ExportIKPublicKey(Mockito.any(), Mockito.eq(2), Mockito.any(EccRefPublicKey.class))) + .thenAnswer(call -> { + EccRefPublicKey output = call.getArgument(2); + output.bits = 256; + Arrays.fill(output.x, (byte) 0x66); + Arrays.fill(output.y, (byte) 0x77); + return 0; + }); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + byte[] data = service.exportIkPublicKey(2, new EccRefPublicKey().size()).getData(); + + Assertions.assertEquals(new EccRefPublicKey().size(), data.length); + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_ExportIKPublicKey"), Mockito.any()); + } + + @Test + void shouldExportIkMacViaSdfeExportIkMac() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_ExportIKMac"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_ExportIKMac(Mockito.any(), Mockito.eq(2), Mockito.any(byte[].class))) + .thenAnswer(call -> { + byte[] out = call.getArgument(2); + Arrays.fill(out, (byte) 0x6A); + return 0; + }); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + byte[] data = service.exportIkMac(2).getData(); + + Assertions.assertEquals(8, data.length); + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_ExportIKMac"), Mockito.any()); + } + + @Test + void shouldSignIkViaSdfeSignIk() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + IkSignRequest request = new IkSignRequest(); + request.setKeyType(2); + request.setData(new byte[] {0x01, 0x02}); + request.setSignatureBufferSize(new EccSignature().size()); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_SignIK"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_SignIK(Mockito.any(), Mockito.eq(2), Mockito.any(byte[].class), Mockito.eq(2), Mockito.any(EccSignature.class))) + .thenAnswer(call -> { + EccSignature signature = call.getArgument(4); + Arrays.fill(signature.r, (byte) 0x12); + Arrays.fill(signature.s, (byte) 0x34); + return 0; + }); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + byte[] data = service.signIk(request).getData(); + + Assertions.assertEquals(new EccSignature().size(), data.length); + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_SignIK"), Mockito.any()); + } + + @Test + void shouldVerifyIkViaSdfeVerifyIk() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + IkVerifyRequest request = new IkVerifyRequest(); + request.setKeyType(2); + request.setData(new byte[] {0x01, 0x02}); + request.setSignature(new byte[new EccSignature().size()]); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_VerifyIK"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_VerifyIK(Mockito.any(), Mockito.eq(2), Mockito.any(byte[].class), Mockito.eq(2), Mockito.any(EccSignature.class))) + .thenReturn(0); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + service.verifyIk(request); + + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_VerifyIK"), Mockito.any()); + } + + @Test + void shouldReadFirmwareInfoViaSdfeGetFirmwareInfo() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_GetFirmwareInfo"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_GetFirmwareInfo(Mockito.any(), Mockito.any(SdfFirmwareInfo.class))) + .thenAnswer(call -> { + SdfFirmwareInfo info = call.getArgument(1); + info.bomInfo[0] = 1; + info.gd32Info[0] = 2; + info.n32s033Info[0] = 3; + return 0; + }); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + FirmwareInfoResult result = service.getFirmwareInfo(); + + Assertions.assertNotNull(result); + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_GetFirmwareInfo"), Mockito.any()); + } + + @Test + void shouldEncryptViaSdfeEncrypt() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + SymmetricCryptoRequest request = new SymmetricCryptoRequest(); + request.setAlgId(1); + request.setKey(new byte[] {0x01, 0x02}); + request.setIv(new byte[16]); + request.setData(new byte[] {0x03, 0x04}); + request.setOutBufferSize(8); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_Encrypt"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_Encrypt(Mockito.any(), Mockito.any(byte[].class), Mockito.eq(2), Mockito.eq(1), + Mockito.any(byte[].class), Mockito.any(byte[].class), Mockito.eq(2), Mockito.any(byte[].class), Mockito.any(IntByReference.class))) + .thenAnswer(call -> { + byte[] out = call.getArgument(7); + IntByReference outLen = call.getArgument(8); + out[0] = 0x55; + out[1] = 0x66; + outLen.setValue(2); + return 0; + }); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + byte[] data = service.sdfeEncrypt(request).getData(); + + Assertions.assertArrayEquals(new byte[] {0x55, 0x66}, data); + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_Encrypt"), Mockito.any()); + } + + @Test + void shouldDecryptViaSdfeDecrypt() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + SymmetricCryptoRequest request = new SymmetricCryptoRequest(); + request.setAlgId(1); + request.setKey(new byte[] {0x01, 0x02}); + request.setIv(new byte[16]); + request.setData(new byte[] {0x03, 0x04}); + request.setOutBufferSize(8); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_Decrypt"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_Decrypt(Mockito.any(), Mockito.any(byte[].class), Mockito.eq(2), Mockito.eq(1), + Mockito.any(byte[].class), Mockito.any(byte[].class), Mockito.eq(2), Mockito.any(byte[].class), Mockito.any(IntByReference.class))) + .thenAnswer(call -> { + byte[] out = call.getArgument(7); + IntByReference outLen = call.getArgument(8); + out[0] = 0x21; + out[1] = 0x22; + outLen.setValue(2); + return 0; + }); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + byte[] data = service.sdfeDecrypt(request).getData(); + + Assertions.assertArrayEquals(new byte[] {0x21, 0x22}, data); + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_Decrypt"), Mockito.any()); + } + + @Test + void shouldHashViaSdfeHash() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + DigestRequest request = new DigestRequest(); + request.setAlgId(1); + request.setData(new byte[] {0x01, 0x02}); + request.setOutBufferSize(8); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_Hash"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_Hash(Mockito.any(), Mockito.eq(1), Mockito.any(byte[].class), Mockito.eq(2), Mockito.any(byte[].class), Mockito.any(IntByReference.class))) + .thenAnswer(call -> { + byte[] out = call.getArgument(4); + IntByReference outLen = call.getArgument(5); + out[0] = 0x0A; + out[1] = 0x0B; + outLen.setValue(2); + return 0; + }); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + byte[] data = service.sdfeHash(request).getData(); + + Assertions.assertArrayEquals(new byte[] {0x0A, 0x0B}, data); + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_Hash"), Mockito.any()); + } + + @Test + void shouldCopyHashStateViaSdfeHashCopy() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + + Mockito.when(sessionTemplate.withTwoSessions(Mockito.eq("SDFE_HashCopy"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.TwoSessionCallback callback = + (PcieSessionTemplate.TwoSessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_HashCopy(Mockito.any(), Mockito.any())).thenReturn(0); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2), Pointer.createConstant(3)); + }); + + service.sdfeHashCopy(); + + Mockito.verify(sessionTemplate).withTwoSessions(Mockito.eq("SDFE_HashCopy"), Mockito.any()); + } + + @Test + void shouldInternalEncryptEccViaSdfeInternalEncrypt() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + EccInternalEncryptRequest request = new EccInternalEncryptRequest(); + request.setKeyIndex(1); + request.setData(new byte[] {0x01, 0x02}); + request.setOutBufferSize(new EccCipher().size()); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_InternalEncrypt_ECC"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_InternalEncrypt_ECC(Mockito.any(), Mockito.eq(1), Mockito.any(byte[].class), Mockito.eq(2), Mockito.any(EccCipher.class))) + .thenAnswer(call -> { + EccCipher cipher = call.getArgument(4); + cipher.l = 2; + cipher.c[0] = 0x01; + cipher.c[1] = 0x02; + return 0; + }); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + BackupDataResult result = service.sdfeInternalEncryptEcc(request); + + Assertions.assertNotNull(result); + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_InternalEncrypt_ECC"), Mockito.any()); + } + + @Test + void shouldInternalDecryptEccViaSdfeInternalDecrypt() { + PcieSessionTemplate sessionTemplate = Mockito.mock(PcieSessionTemplate.class); + CryptoCardProperties properties = new CryptoCardProperties(); + JnaPcieCryptoService service = new JnaPcieCryptoService(sessionTemplate, properties); + EccInternalDecryptRequest request = new EccInternalDecryptRequest(); + request.setKeyIndex(1); + request.setCipherBlob(new byte[new EccCipher().size()]); + request.setOutBufferSize(8); + + Mockito.when(sessionTemplate.withSession(Mockito.eq("SDFE_InternalDecrypt_ECC"), Mockito.any())) + .thenAnswer(invocation -> { + @SuppressWarnings("unchecked") + PcieSessionTemplate.SessionCallback callback = + (PcieSessionTemplate.SessionCallback) invocation.getArgument(1); + PcieNativeLibrary lib = Mockito.mock(PcieNativeLibrary.class); + Mockito.when(lib.SDFE_InternalDecrypt_ECC(Mockito.any(), Mockito.eq(1), Mockito.any(EccCipher.class), Mockito.any(byte[].class), Mockito.any(IntByReference.class))) + .thenAnswer(call -> { + byte[] out = call.getArgument(3); + IntByReference outLen = call.getArgument(4); + out[0] = 0x31; + out[1] = 0x32; + outLen.setValue(2); + return 0; + }); + return callback.apply(lib, Pointer.createConstant(1), Pointer.createConstant(2)); + }); + + byte[] data = service.sdfeInternalDecryptEcc(request).getData(); + + Assertions.assertArrayEquals(new byte[] {0x31, 0x32}, data); + Mockito.verify(sessionTemplate).withSession(Mockito.eq("SDFE_InternalDecrypt_ECC"), Mockito.any()); + } } diff --git a/src/test/java/com/cisd/tms/modules/device/controller/CryptoCardControllerTest.java b/src/test/java/com/cisd/tms/modules/device/controller/CryptoCardControllerTest.java index 727312f..1402ded 100644 --- a/src/test/java/com/cisd/tms/modules/device/controller/CryptoCardControllerTest.java +++ b/src/test/java/com/cisd/tms/modules/device/controller/CryptoCardControllerTest.java @@ -49,6 +49,15 @@ class CryptoCardControllerTest { assertFalse(helperMethods.contains("normalizeBinary")); } + @Test + void shouldRemoveEncryptedRsaImportEndpoint() { + java.util.Set controllerMethods = java.util.Arrays.stream(CryptoCardController.class.getDeclaredMethods()) + .map(java.lang.reflect.Method::getName) + .collect(java.util.stream.Collectors.toSet()); + + assertFalse(controllerMethods.contains("importEncryptedKeyPairRsa")); + } + @Test void shouldReturnDeviceStatusAsHex() throws Exception { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); diff --git a/src/test/java/com/cisd/tms/modules/mk/service/LmkServiceTest.java b/src/test/java/com/cisd/tms/modules/mk/service/LmkServiceTest.java index 261a87e..87e7694 100644 --- a/src/test/java/com/cisd/tms/modules/mk/service/LmkServiceTest.java +++ b/src/test/java/com/cisd/tms/modules/mk/service/LmkServiceTest.java @@ -1,10 +1,14 @@ package com.cisd.tms.modules.mk.service; import com.cisd.tms.integration.crypto.pcie.Gm0018AlgorithmIds; +import com.cisd.tms.integration.crypto.pcie.jna.EccRefPublicKey; +import com.cisd.tms.integration.crypto.pcie.jna.SdfeIkComponent; import com.cisd.tms.integration.crypto.pcie.model.BackupDataResult; import com.cisd.tms.integration.crypto.pcie.model.DigestRequest; import com.cisd.tms.integration.crypto.pcie.model.EccInternalSignRequest; import com.cisd.tms.integration.crypto.pcie.model.EccInternalVerifyRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkSignRequest; +import com.cisd.tms.integration.crypto.pcie.model.IkVerifyRequest; import com.cisd.tms.integration.crypto.pcie.model.RecoverUserKeyRequest; import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService; import com.cisd.tms.modules.mk.config.MasterKeyInitProperties; @@ -87,6 +91,24 @@ class LmkServiceTest { Assertions.assertEquals("aabb", result.getSeedMac()); } + @Test + void shouldExportIkPublicKeyHexViaDedicatedIkApi() { + PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); + MasterKeyInitProperties properties = configuredPins("MTIzNDU2Nzg=", "ODc2NTQzMjE="); + BackupDataResult publicKey = new BackupDataResult(); + publicKey.setLength(new EccRefPublicKey().size()); + publicKey.setData(sequentialBytes(new EccRefPublicKey().size(), 0x31)); + Mockito.when(pcieCryptoService.exportIkPublicKey(2, new EccRefPublicKey().size())).thenReturn(publicKey); + + LmkService service = new LmkServiceImpl(pcieCryptoService, properties); + + String result = service.exportIkPublicKeyHex(); + + Assertions.assertEquals(org.bouncycastle.util.encoders.Hex.toHexString(publicKey.getData()), result); + Mockito.verify(pcieCryptoService).exportIkPublicKey(2, new EccRefPublicKey().size()); + Mockito.verify(pcieCryptoService, Mockito.never()).exportSignPublicKeyEcc(Mockito.anyInt(), Mockito.anyInt()); + } + @Test void shouldBuildBackupPacketForSingleComponentIndex() { PcieCryptoService pcieCryptoService = Mockito.mock(PcieCryptoService.class); @@ -100,11 +122,11 @@ class LmkServiceTest { 0x09, 0x0A, 0x0B, 0x0C }); BackupDataResult ikAuthBackup = new BackupDataResult(); - ikAuthBackup.setLength(200); - ikAuthBackup.setData(sequentialBytes(200, 0x21)); + ikAuthBackup.setLength(new SdfeIkComponent().size()); + ikAuthBackup.setData(sequentialBytes(new SdfeIkComponent().size(), 0x21)); BackupDataResult ikDeviceBackup = new BackupDataResult(); - ikDeviceBackup.setLength(200); - ikDeviceBackup.setData(sequentialBytes(200, 0x41)); + ikDeviceBackup.setLength(new SdfeIkComponent().size()); + ikDeviceBackup.setData(sequentialBytes(new SdfeIkComponent().size(), 0x41)); BackupDataResult userSignBackup = new BackupDataResult(); userSignBackup.setLength(12); userSignBackup.setData(new byte[] {0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C}); @@ -129,11 +151,27 @@ class LmkServiceTest { org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikAuthBackup.getData(), 64, 128)), packet.getIkAuth().getComponent() ); + Assertions.assertEquals( + org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikAuthBackup.getData(), 200, 332)), + packet.getIkAuth().getPublicKey() + ); + Assertions.assertEquals( + org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikAuthBackup.getData(), 332, 340)), + packet.getIkAuth().getPublicKeyMac() + ); Assertions.assertEquals(1, packet.getIkDevice().getKeyType()); Assertions.assertEquals( org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikDeviceBackup.getData(), 64, 128)), packet.getIkDevice().getComponent() ); + Assertions.assertEquals( + org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikDeviceBackup.getData(), 200, 332)), + packet.getIkDevice().getPublicKey() + ); + Assertions.assertEquals( + org.bouncycastle.util.encoders.Hex.toHexString(java.util.Arrays.copyOfRange(ikDeviceBackup.getData(), 332, 340)), + packet.getIkDevice().getPublicKeyMac() + ); Assertions.assertEquals(2, packet.getUserKeys().size()); Assertions.assertEquals("65666768", packet.getUserKeys().get(0).getComponent()); Assertions.assertEquals("75767778", packet.getUserKeys().get(1).getComponent()); @@ -148,8 +186,8 @@ class LmkServiceTest { MasterKeyBackupPacket packet1 = new MasterKeyBackupPacket(); packet1.setComponentIndex(1); packet1.setLmk(new MasterKeyPacketLmkPart("1112131415161718", "0102")); - packet1.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1112")); - packet1.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2122")); + packet1.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1112", "31323334", "4142434445464748")); + packet1.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2122", "51525354", "6162636465666768")); packet1.setUserKeys(List.of( new MasterKeyPacketUserKeyPart(1, 0, "0102"), new MasterKeyPacketUserKeyPart(1, 1, "1112") @@ -158,8 +196,8 @@ class LmkServiceTest { MasterKeyBackupPacket packet2 = new MasterKeyBackupPacket(); packet2.setComponentIndex(2); packet2.setLmk(new MasterKeyPacketLmkPart("1112131415161718", "0304")); - packet2.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1314")); - packet2.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2324")); + packet2.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1314", "31323334", "4142434445464748")); + packet2.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2324", "51525354", "6162636465666768")); packet2.setUserKeys(List.of( new MasterKeyPacketUserKeyPart(1, 0, "0304"), new MasterKeyPacketUserKeyPart(1, 1, "1314") @@ -168,8 +206,8 @@ class LmkServiceTest { MasterKeyBackupPacket packet3 = new MasterKeyBackupPacket(); packet3.setComponentIndex(3); packet3.setLmk(new MasterKeyPacketLmkPart("1112131415161718", "0506")); - packet3.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1516")); - packet3.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2526")); + packet3.setIkAuth(new MasterKeyPacketIkPart(2, "2122232425262728", "1516", "31323334", "4142434445464748")); + packet3.setIkDevice(new MasterKeyPacketIkPart(1, "3132333435363738", "2526", "51525354", "6162636465666768")); packet3.setUserKeys(List.of( new MasterKeyPacketUserKeyPart(1, 0, "0506"), new MasterKeyPacketUserKeyPart(1, 1, "1516") @@ -196,8 +234,8 @@ class LmkServiceTest { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }, lmkCaptor.getValue()); - Assertions.assertArrayEquals(hex("1112131415162122232425262728"), ikAuthCaptor.getValue()); - Assertions.assertArrayEquals(hex("2122232425263132333435363738"), ikDeviceCaptor.getValue()); + Assertions.assertArrayEquals(hex("1112131415162122232425262728313233344142434445464748"), ikAuthCaptor.getValue()); + Assertions.assertArrayEquals(hex("2122232425263132333435363738515253546162636465666768"), ikDeviceCaptor.getValue()); Assertions.assertEquals(2, userKeyCaptor.getAllValues().size()); Assertions.assertArrayEquals(hex("010203040506"), userKeyCaptor.getAllValues().get(0).getEncryptedKey()); Assertions.assertArrayEquals(hex("111213141516"), userKeyCaptor.getAllValues().get(1).getEncryptedKey()); @@ -219,7 +257,7 @@ class LmkServiceTest { signResult.setLength(2); signResult.setData(new byte[] {(byte) 0xAA, (byte) 0xBB}); Mockito.when(pcieCryptoService.digest(Mockito.any())).thenReturn(digestResult); - Mockito.when(pcieCryptoService.eccInternalSign(Mockito.any())).thenReturn(signResult); + Mockito.when(pcieCryptoService.signIk(Mockito.any())).thenReturn(signResult); LmkService service = new LmkServiceImpl(pcieCryptoService, properties); @@ -227,13 +265,14 @@ class LmkServiceTest { Assertions.assertEquals("aabb", signatureHex); ArgumentCaptor digestCaptor = ArgumentCaptor.forClass(DigestRequest.class); - ArgumentCaptor signCaptor = ArgumentCaptor.forClass(EccInternalSignRequest.class); + ArgumentCaptor signCaptor = ArgumentCaptor.forClass(IkSignRequest.class); InOrder inOrder = Mockito.inOrder(pcieCryptoService); inOrder.verify(pcieCryptoService).digest(digestCaptor.capture()); - inOrder.verify(pcieCryptoService).eccInternalSign(signCaptor.capture()); + inOrder.verify(pcieCryptoService).signIk(signCaptor.capture()); Assertions.assertEquals(Gm0018AlgorithmIds.SM3, digestCaptor.getValue().getAlgId()); Assertions.assertArrayEquals("1223".getBytes(StandardCharsets.UTF_8), digestCaptor.getValue().getData()); Assertions.assertArrayEquals(digestResult.getData(), signCaptor.getValue().getData()); + Assertions.assertEquals(2, signCaptor.getValue().getKeyType()); } @Test @@ -255,14 +294,15 @@ class LmkServiceTest { service.verifyIk("1223", "aabb"); ArgumentCaptor digestCaptor = ArgumentCaptor.forClass(DigestRequest.class); - ArgumentCaptor verifyCaptor = ArgumentCaptor.forClass(EccInternalVerifyRequest.class); + ArgumentCaptor verifyCaptor = ArgumentCaptor.forClass(IkVerifyRequest.class); InOrder inOrder = Mockito.inOrder(pcieCryptoService); inOrder.verify(pcieCryptoService).digest(digestCaptor.capture()); - inOrder.verify(pcieCryptoService).eccInternalVerify(verifyCaptor.capture()); + inOrder.verify(pcieCryptoService).verifyIk(verifyCaptor.capture()); Assertions.assertEquals(Gm0018AlgorithmIds.SM3, digestCaptor.getValue().getAlgId()); Assertions.assertArrayEquals("1223".getBytes(StandardCharsets.UTF_8), digestCaptor.getValue().getData()); Assertions.assertArrayEquals(digestResult.getData(), verifyCaptor.getValue().getData()); Assertions.assertArrayEquals(new byte[] {(byte) 0xAA, (byte) 0xBB}, verifyCaptor.getValue().getSignature()); + Assertions.assertEquals(2, verifyCaptor.getValue().getKeyType()); } private static MasterKeyInitProperties configuredPins(String oldPinBase64, String newPinBase64) {