Attention une mise à jour du service Gitlab va être effectuée le mardi 30 novembre entre 17h30 et 18h00. Cette mise à jour va générer une interruption du service dont nous ne maîtrisons pas complètement la durée mais qui ne devrait pas excéder quelques minutes. Cette mise à jour intermédiaire en version 14.0.12 nous permettra de rapidement pouvoir mettre à votre disposition une version plus récente.

Commit 1a8135ec authored by calocedre TAC's avatar calocedre TAC
Browse files

renaming + split responsibilities

parent 3d9e27d2
......@@ -22,6 +22,17 @@
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.58</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
<groupId>commons-net</groupId>
......@@ -35,6 +46,12 @@
<version>5.7.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.19.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
......
......@@ -5,39 +5,47 @@ package fr.inria.clea.lsp;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.ECGenParameterSpec;
import java.security.KeyFactory;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.UUID;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.generators.KDF1BytesGenerator;
import org.bouncycastle.crypto.params.ISO18033KDFParameters;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.ISO18033KDFParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import lombok.extern.slf4j.Slf4j;
/**
* Encryption/Decription respecting ECIES-KEM (Elliptic Curve Integrated
* Encryption Scheme with Key encapsulation mechanisms )
......@@ -50,21 +58,18 @@ import org.bouncycastle.util.encoders.Hex;
* for Public-Key Encryption”, 2006</a>
*
*/
public class Ecies {
@Slf4j
public class CleaEciesEncoder {
/* Type of the elliptic curve */
private final String curveName = "secp256r1";
/* Parameter iv fixed 96-bits for AES-256-GCM */
private final byte[] iv = { (byte) 0xf0, (byte) 0xf1, (byte) 0xf2, (byte) 0xf3, (byte) 0xf4, (byte) 0xf5,
(byte) 0xf6, (byte) 0xf7, (byte) 0xf8, (byte) 0xf9, (byte) 0xfa, (byte) 0xfb };
/* Display or not on console intermediate results */
boolean debug;
/* Size in bytes of the ephemeral public key */
public static final int C0_BYTES_SIZE = 33;
/*
* Size in bytes of data header not encrypted (additionnal data in AES-256-GCM)
*/
/* Size in bytes of data header not encrypted (additional data in AES-256-GCM) */
public static final int HEADER_BYTES_SIZE = 17;
/* Size in bytes of the message to be encrypted with AES-256-GCM */
public static final int MSG_BYTES_SIZE = 44;
......@@ -73,28 +78,20 @@ public class Ecies {
/* Size in bytes of locContactMsg to be encrypted with AES-256-GCM */
public static final int LOC_BYTES_SIZE = 16;
/**
* Constructor
*
* @param debug display intermediate results for debug purpose
*/
public Ecies(boolean debug) throws Exception {
public CleaEciesEncoder() {
Security.addProvider(new BouncyCastleProvider());
this.debug = debug;
}
/**
* generate a keys pair (private/public) for decryption/encryption
*
* @param pubkey_compressed True to get the compressed format of the public key
* @param publicKeyCompressed True to get the compressed format of the public key
* i.e. [02 or 03 | X] otherwise in uncompressed format
* i.e. [04|X|Y]
*
* @return String[2] = [privateKey, publicKey]
*/
public String[] genKeysPair(boolean pubkey_compressed) throws Exception {
public String[] genKeysPair(boolean publicKeyCompressed) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
kpg.initialize(new ECGenParameterSpec(curveName), new SecureRandom());
KeyPair keyPair = kpg.generateKeyPair();
......@@ -103,21 +100,21 @@ public class Ecies {
String[] keyspair = new String[2];
keyspair[0] = privKey.getD().toString(16);
keyspair[1] = Hex.toHexString(pubKey.getQ().getEncoded(pubkey_compressed));
keyspair[1] = Hex.toHexString(pubKey.getQ().getEncoded(publicKeyCompressed));
return keyspair;
}
/**
* Generate an EC private key (ECPrivateKey)
* Get an EC private key (ECPrivateKey)
*
* @param privkey string format of the key
* @param privateKey string format of the key
*
* @return ECPrivateKey
*/
private ECPrivateKey genPrivateKey(String privkey) throws Exception {
private ECPrivateKey getECPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
BigInteger keyInt = new BigInteger(privkey, 16);
BigInteger keyInt = new BigInteger(privateKey, 16);
ECParameterSpec ecParameterSpec = ECNamedCurveTable.getParameterSpec(curveName);
ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(keyInt, ecParameterSpec);
......@@ -128,13 +125,15 @@ public class Ecies {
}
/**
* Generate an EC public key (ECPublicKey)
* Get an EC public key (ECPublicKey)
*
* @param pubkey string format of the key
* @param publicKey string format of the key
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
private ECPublicKey genPublicKey(String pubkey) throws Exception {
private ECPublicKey getECPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] keyBytes = Hex.decode(pubkey);
byte[] keyBytes = Hex.decode(publicKey);
ECParameterSpec ecParameterSpec = ECNamedCurveTable.getParameterSpec(curveName);
ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(ecParameterSpec.getCurve().decodePoint(keyBytes),
ecParameterSpec);
......@@ -149,16 +148,19 @@ public class Ecies {
* SHA256 hash as KDF - AES-256-GCM with a fixed 96-bits IV as DEM and TAG.
*
* @param header First HEADER_BYTES_SIZE bytes in Cléa protocol take as associated data in the
* scheme. If null no additionnal data required
* scheme. If null no additional data required
* @param message Message of MSG_BYTES_SIZE bytes in Cléa protocol
* @param Pubkey EC public key required for encryption in String format
* @param publicKey EC public key required for encryption in String format
*
* @return return data encrypted [header | encrypted message with tag |
* C0=ephemeral public key]
* @throws IOException
*/
public byte[] encrypt(byte[] header, byte[] message, String Pubkey) throws Exception {
public byte[] encrypt(byte[] header, byte[] message, String publicKey)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException,
InvalidAlgorithmParameterException, IllegalStateException, InvalidCipherTextException, IOException {
/* Public Key */
ECPublicKey Pub = genPublicKey(Pubkey);
ECPublicKey ecPublicKey = getECPublicKey(publicKey);
/* Generate C0 */
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
kpg.initialize(new ECGenParameterSpec(curveName), new SecureRandom());
......@@ -168,7 +170,7 @@ public class Ecies {
byte C0[] = C0_Q.getEncoded(true); // C0 = E(r * G)
/* Generate secret S */
ECPoint S_Q = Pub.getQ().multiply(r); // S = r * D(PK_HA)
ECPoint S_Q = ecPublicKey.getQ().multiply(r); // S = r * D(PK_HA)
byte S[] = S_Q.getEncoded(true); // E(S)
/* Generate AES key using KDF1 */
......@@ -199,22 +201,23 @@ public class Ecies {
* Decrypt data respecting ECIES-KEM using: - SECP256R1 ECDH as KEM - KDF1 using
* SHA256 hash as KDF - AES-256-GCM with a fixed 96-bits IV as DEM and TAG.
*
* @param encrypted_msg Message of 44 bytes in Cléa protocol
* @param Privkey EC private key required for decryption in String format
* @param encryptedMessage Message of 44 bytes in Cléa protocol
* @param privateKeyString EC private key required for decryption in String format
* @param header indicates if there is an header (HEADER_BYTES_SIZE) as
* additionnal data or not
* @return return data decrypted [header | decrypted message]
*/
public byte[] decrypt(byte[] encrypted_msg, String Privkey, boolean header) throws Exception {
public byte[] decrypt(byte[] encryptedMessage, String privateKeyString, boolean header)
throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, IllegalStateException, InvalidCipherTextException {
/* Private Key */
ECPrivateKey Priv = genPrivateKey(Privkey);
ECPrivateKey privateKey = getECPrivateKey(privateKeyString);
/* Get C0 */
ECParameterSpec ecParameterSpec = ECNamedCurveTable.getParameterSpec(curveName);
byte C0[] = Arrays.copyOfRange(encrypted_msg, encrypted_msg.length - C0_BYTES_SIZE, encrypted_msg.length);
byte C0[] = Arrays.copyOfRange(encryptedMessage, encryptedMessage.length - C0_BYTES_SIZE, encryptedMessage.length);
ECPoint C0_Q = ecParameterSpec.getCurve().decodePoint(C0);
/* Generate secret S */
ECPoint S_Q = C0_Q.multiply(Priv.getD()); // S = x * D(C0)
ECPoint S_Q = C0_Q.multiply(privateKey.getD()); // S = x * D(C0)
byte S[] = S_Q.getEncoded(true); // E(S)
/* Generate AES key using KDF1 */
......@@ -232,15 +235,15 @@ public class Ecies {
int pos;
/* With or without header as additional data */
if (header) {
out = new byte[encrypted_msg.length - C0_BYTES_SIZE - HEADER_BYTES_SIZE - TAG_BYTES_SIZE];
cipher.processAADBytes(encrypted_msg, 0, HEADER_BYTES_SIZE);
pos = cipher.processBytes(encrypted_msg, HEADER_BYTES_SIZE,
encrypted_msg.length - C0_BYTES_SIZE - HEADER_BYTES_SIZE, out, 0);
out = new byte[encryptedMessage.length - C0_BYTES_SIZE - HEADER_BYTES_SIZE - TAG_BYTES_SIZE];
cipher.processAADBytes(encryptedMessage, 0, HEADER_BYTES_SIZE);
pos = cipher.processBytes(encryptedMessage, HEADER_BYTES_SIZE,
encryptedMessage.length - C0_BYTES_SIZE - HEADER_BYTES_SIZE, out, 0);
cipher.doFinal(out, pos);
out = concat(Arrays.copyOfRange(encrypted_msg, 0, HEADER_BYTES_SIZE), out);
out = concat(Arrays.copyOfRange(encryptedMessage, 0, HEADER_BYTES_SIZE), out);
} else {
out = new byte[encrypted_msg.length - C0_BYTES_SIZE - TAG_BYTES_SIZE];
pos = cipher.processBytes(encrypted_msg, 0, encrypted_msg.length - C0_BYTES_SIZE, out, 0);
out = new byte[encryptedMessage.length - C0_BYTES_SIZE - TAG_BYTES_SIZE];
pos = cipher.processBytes(encryptedMessage, 0, encryptedMessage.length - C0_BYTES_SIZE, out, 0);
cipher.doFinal(out, pos);
}
......@@ -270,7 +273,7 @@ public class Ecies {
* @param bytes 32 bytes array
* @return UUID
*/
protected UUID BytesasUuid(byte[] bytes) {
protected UUID bytesToUuid(byte[] bytes) {
ByteBuffer bb = ByteBuffer.wrap(bytes);
long firstLong = bb.getLong();
long secondLong = bb.getLong();
......@@ -284,12 +287,12 @@ public class Ecies {
* @param uuid UUID
* @return 32 bytes array
*/
protected byte[] UuidasBytes(UUID uuid) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
protected byte[] uuidToBytes(UUID uuid) {
ByteBuffer buffer = ByteBuffer.wrap(new byte[16]);
buffer.putLong(uuid.getMostSignificantBits());
buffer.putLong(uuid.getLeastSignificantBits());
return bb.array();
return buffer.array();
}
/**
......@@ -299,52 +302,64 @@ public class Ecies {
* @return 32 bytes array
*/
private static byte[] intToBytes(int data) {
return new byte[] { (byte) ((data >> 24) & 0xff), (byte) ((data >> 16) & 0xff), (byte) ((data >> 8) & 0xff),
(byte) ((data >> 0) & 0xff), };
return new byte[] {
(byte) ((data >> 24) & 0xff),
(byte) ((data >> 16) & 0xff),
(byte) ((data >> 8) & 0xff),
(byte) ((data >> 0) & 0xff) };
}
/**
* Compute the LTKey (Temporary Location Key) respecting Cléa protocol
* LTKey(t_periodStart) = SHA256(SK_L | t_periodStart)
*
* @param t_periodStart Starting time of the period in seconds(NTP timestamp
* @param periodStartTime Starting time of the period in seconds(NTP timestamp
* limited to the 32-bit seconds field)
* @param SK_L Permanent location secret key (hexastring format)
* @param permanentLocationSecretKey Permanent location secret key (hexastring format)
* @return LTKey (Temporary Location Key)
* @throws CleaEncryptionException
*/
public byte[] compute_LTKey(int t_periodStart, String SK_L) throws Exception {
final byte[] concatKey = this.concat(intToBytes(t_periodStart), Hex.decode(SK_L));
MessageDigest msg = MessageDigest.getInstance("SHA-256");
byte[] LTKey = msg.digest(concatKey);
return LTKey;
public byte[] computeLocationTemporarySecretKey(String permanentLocationSecretKey, int periodStartTime) throws CleaEncryptionException {
try {
byte[] concatKey = this.concat(intToBytes(periodStartTime), Hex.decode(permanentLocationSecretKey));
MessageDigest msg = MessageDigest.getInstance("SHA-256");
byte[] locationTemporarySecretKey = msg.digest(concatKey);
return locationTemporarySecretKey;
} catch (IOException | NoSuchAlgorithmException e) {
log.error("Error when computing location temporary secret key!", e);
throw new CleaEncryptionException(e);
}
}
/**
* Compute the LTId (Temporary Location UUID) respecting Cléa protocol
* LTId(t_periodStart) = HMAC-SHA-256-128(LTKey(t_periodStart), "1")
*
* @param LTKey (Temporary Location Key)
* @param locationTemporarySecretKey (Temporary Location Key)
* @return LTId (Temporary Location UUID)
* @throws CleaEncryptionException
*/
public UUID compute_LTId(byte[] LTKey) throws Exception {
UUID LTId;
Mac hmacSha256;
/* LTId(t_periodStart) = HMAC-SHA-256-128(LTKey(t_periodStart), "1") */
hmacSha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(LTKey, "HmacSHA256");
hmacSha256.init(secretKeySpec);
String message = "1";
byte[] tlidB = hmacSha256.doFinal(message.getBytes("UTF-8"));
/* Convert in UUID format */
byte[] tlidBTrunc = Arrays.copyOfRange(tlidB, 0, 16);
LTId = UUID.nameUUIDFromBytes(tlidBTrunc);
return LTId;
public UUID computeLocationTemporaryPublicId(byte[] locationTemporarySecretKey) throws CleaEncryptionException {
try {
UUID locationTemporaryPublicID;
Mac hmacSha256;
/* LTId(t_periodStart) = HMAC-SHA-256-128(LTKey(t_periodStart), "1") */
hmacSha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(locationTemporarySecretKey, "HmacSHA256");
hmacSha256.init(secretKeySpec);
String message = "1";
byte[] tlidB = hmacSha256.doFinal(message.getBytes("UTF-8"));
/* Convert in UUID format */
byte[] tlidBTrunc = Arrays.copyOfRange(tlidB, 0, 16);
locationTemporaryPublicID = UUID.nameUUIDFromBytes(tlidBTrunc);
return locationTemporaryPublicID;
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | UnsupportedEncodingException e) {
log.error("Error when computing location temporary secret key!", e);
throw new CleaEncryptionException(e);
}
}
}
package fr.inria.clea.lsp;
/**
* Generic Clea exception thrown when something went wrong while encoding / decoding.
*/
public class CleaEncryptionException extends Exception {
private static final long serialVersionUID = 1L;
public CleaEncryptionException(Throwable cause) {
super(cause);
}
}
/*
* Copyright (C) Inria, 2021
*/
package fr.inria.clea.lsp;
import java.util.UUID;
import fr.devnied.bitlib.BytesUtils;
/**
* locationSpecificPart (LSP) contents data respecting the CLEA protocol
*
* @see <a href="https://hal.inria.fr/hal-03146022">CLEA protocol</a>
*
*/
class Data {
/* Protocol version */
int version;
/*
* LSP type, in order to be able to use multiple formats in parallel in the
* future.
*/
int LSPtype;
/*
* Location Temporary public universally unique Identifier (UUID), specific to a
* given location at a given period.
*/
UUID LTId;
/* 0/1 regular users or staff member of the location */
int staff;
/* 0/1 indicates the locContactMsg is absent/present in the Msg */
int locContactMsgPresent;
/*
* Country code, coded as the ISO 3166-1 country code, for instance 0x250 for
* France
*/
int countryCode;
/*
* qrCodeRenewalInterval value in a compact manner, as the exponent of a power
* of two.
*/
int CRIexp;
/* Type of the location/venue */
int venueType;
/* Reserved: a first level of venue category */
int venueCategory1;
/* Reserved: a second level of venue category */
int venueCategory2;
/* Duration, in terms of number of hours, of the period */
int periodDuration;
/* Starting time of the period in a compressed manner (round hour) */
int ct_periodStart;
/* Starting time of the QR code validity timespan in seconds */
int t_qrStart;
/* Temporary location key for the period */
byte[] LTKey = new byte[32];
/* Phone number of the location contact person, one digit = one character */
String locationPhone;
/* Secret 8 digit PIN, one digit = one character */
String locationPIN;
/* Starting time of the period in seconds */
int t_periodStart;
/**
* Set LSP parameters
*
* @param staff [0-1] regular users or staff member of the location
* @param countryCode [0-0x0f/15] Country code, for instance 0x250 for France
* @param CRIexp [0-0x1f/31] qrCodeRenewalInterval value in a compact
* manner, as the exponent of a power of two.
* @param venueType [0-0x1f/31] Type of the location/venue
* @param venueCategory1 [0-0x0f/15] Reserved: a first level of venue category
* @param venueCategory2 [0-0x0f/15] Reserved: a first level of venue category
* @param periodDuration [0-0xff/255] Duration, in terms of number of hours, of
* the period
* @param locationPhone [String of 16 digit max] Phone number of the location
* contact perso
* @param locationPIN [String of 8 digit] Secret 8 digit PIN
*
*/
public void setParam(int staff, int countryCode, int CRIexp, int venueType, int venueCategory1, int venueCategory2,
int periodDuration, String locationPhone, String locationPIN) {
this.version = 0x0;
this.LSPtype = 0x0;
this.staff = staff;
this.locContactMsgPresent = 0x1;
this.countryCode = countryCode;
this.CRIexp = CRIexp;
this.venueType = venueType;
this.venueCategory1 = venueCategory1;
this.venueCategory2 = venueCategory2;
this.periodDuration = periodDuration;
this.locationPhone = locationPhone;
this.locationPIN = locationPIN;
}
/**
* Set LSP parameters
*
* @param staff [0-1] regular users or staff member of the location
* @param countryCode [0-0x0f/15] Country code, for instance 0x250 for France
* @param CRIexp [0-0x1f/31] qrCodeRenewalInterval value in a compact
* manner, as the exponent of a power of two.
* @param venueType [0-0x1f/31] Type of the location/venue
* @param venueCategory1 [0-0x0f/15] Reserved: a first level of venue category
* @param venueCategory2 [0-0x0f/15] Reserved: a first level of venue category
* @param periodDuration [0-0xff/255] Duration, in terms of number of hours, of
* the period
*
*/
public void setParam(int staff, int countryCode, int CRIexp, int venueType, int venueCategory1, int venueCategory2,
int periodDuration) {
this.version = 0x0;
this.LSPtype = 0x0;
this.staff = staff;
this.locContactMsgPresent = 0x0;
this.countryCode = countryCode;
this.CRIexp = CRIexp;
this.venueType = venueType;
this.venueCategory1 = venueCategory1;
this.venueCategory2 = venueCategory2;
this.periodDuration = periodDuration;
this.locationPhone = "";
this.locationPIN = "";
}
/**
* Display bytes array on console for debug purpose
*
* @param label header on display
* @param data byte array to be display with a sequence of bytes
*/
public void Display(String label, byte[] data) {
System.out.println(label);
System.out.println("-----------------");
System.out.println(BytesUtils.bytesToString(data));
System.out.println("-----------------");
}
/**
* Display LSP data parameters for debug purpose
*
* @param label header on display
*/
public void displayData(String label) {
System.out.println(label);
System.out.println("-----------------");
System.out.println("version:" + this.version + " LSPType:" + this.LSPtype + " LTId:" + this.LTId.toString());
System.out.print("staff:" + this.staff + " C:" + this.locContactMsgPresent + " countryCode:" + this.countryCode
+ " CRIexp:" + this.CRIexp);
System.out.println(" venueType:" + this.venueType + " venueCategory1:" + this.venueCategory1
+ " venueCategory2:" + this.venueCategory2);
System.out.println("periodDuration:" + this.periodDuration + " t_qrStart:" + this.t_qrStart + " ct_periodStart:"
+ this.ct_periodStart);
System.out.println("LTKey:" + BytesUtils.bytesToString(this.LTKey));
if (this.locContactMsgPresent == 1) {
System.out.println("locationPhone:" + this.locationPhone + " locationPIN:" + this.locationPIN
+ " t_periodStart:" + this.t_periodStart);
}
System.out.println("-----------------");
}
}
/*
* Copyright (C) Inria, 2021
*/
package fr.inria.clea.lsp;
import java.util.Arrays;
import java.util.Base64;
import fr.devnied.bitlib.BitUtils;
/**