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 f5d51eb1 authored by Cypres TAC's avatar Cypres TAC
Browse files

Merge branch 'java-enhancements' into 'master'

renaming + split responsibilities

See merge request !4
parents a441f0af 1ab77f30
Pipeline #226152 passed with stages
in 3 minutes and 8 seconds
......@@ -12,56 +12,58 @@ This Proof of Concept can be used as a basis for:
* To be used as an example to generate the location Specific Part for tablets, if required
* To be used as an example to decode the location Specific Part
### Dependencies
### Highlighted Dependencies
* https://github.com/devnied/Bit-lib4j
* bits and bytes manipulation
* Apache License 2.0
* https://www.bouncycastle.org/fr/
* https://github.com/bcgit/bc-java
* crypto library
* license is an adaptation of the MIT X11 License and should be read as such.
* https://commons.apache.org/proper/commons-net/
* timestamp NTP
* Apache license 2.0
* https://github.com/devnied/Bit-lib4j
* bits and bytes manipulation
* Apache License 2.0
* https://opensource.google/projects/zxing
* Qrcode image generation
* use only for tests (test5)
* Apache License 2.0
All dependencies are noted in the `pom.xml`
### Files description
* `Data.java`: Parameters stored in the LSP
* `Ecies.java`: Encryption algorithms and Elliptical Keys. Implementation of the scheme based on ISO18033-2 with the characteristics set by Cléa: encapsulation of ECIES-KEM keys, the SECP256R1 curve is used for the ECDH key pair, KDF1 based on HMAC-SHA256 and DEM based on AES-256-CTR.
* `Encode.java`: LSP Encoding in base64 using parameters and time. Daughter class of Data and containing an Ecies instance.
* `Decode.java`: Decoding of a Qrcode in base64 to extract all the parameters. Daughter class of Data and containing an Ecies instance.
* `Test.java`: Package Tests
* `utils/TimeUtils.java`:
* `CleaEciesEncoder.java`: Encryption/Decription respecting ECIES-KEM (Elliptic Curve Integrated Encryption Scheme with Key encapsulation mechanisms)
* `CleaEncryptionException.java`: Generic Clea exception thrown when something went wrong while encoding / decoding.
* `Location.java`: Location QRcode management
* `LocationContact.java`: Location Contact data (phone number, pin code, starting time) in plain text
* `LocationContactMessageEncoder.java`: LocationContact encoding/decoding
* `LocationSpecificPart.java`: Location Specific Part data in plain text
* `LocationSpecificPartEncoder.java`: Location Specific Part encoding
* `LocationSpecificPartDecoder.java`: Location Specific Part decoding
* `LspEncoderDecoder.java`: Main executable used for encoding)/Java(decoding) operability tests
### Installation and Use
* clone the project and install it (`mvn install`)
* `java -cp target/clea-lsp-0.0.1-SNAPSHOT-jar-with-dependencies.jar clea.lsp.Test`
* clone the project and test it
* test: `mvn test`
* install: `mvn package`
Possibility to use encoding and decoding of a LSP using the main executable (`LspEncoderDecoder.java`)
* `java -cp java/target/clea-lsp-0.0.1-SNAPSHOT-jar-with-dependencies.jar fr.inria.clea.lsp.LspEncoderDecoder`
* `Usage: LspEncoderDecoder [read qrcode64 privKey] [build staff countryCode CRIexp venueType venueCategory1 venueCategory2 periodDuration pubkey]`
* the result is displayed on the console
* used for C(encoding)/Java(decoding) operability tests in the project `../test`.
* to run tests: `mvn test`
## TODO
* Assert on BitUtils size (verification)
* Assert on bit size parameters
* Exceptions recovery
* Modification for JS lib compatibility
* More tests
## Useful web links
* https://julien-millau.fr/projects/Manipulation-de-bit.html
* https://github.com/devnied/Bit-lib4j
* https://stackoverflow.com/questions/17893609/convert-uuid-to-byte-that-works-when-using-uuid-nameuuidfrombytesb
* https://www.service-public.fr/professionnels-entreprises/vosdroits/F32351
* http://koclab.cs.ucsb.edu/teaching/cren/project/2013/xia2.pdf
* https://www.nominet.uk/how-elliptic-curve-cryptography-encryption-works/
* http://digital.csic.es/bitstream/10261/32671/1/V2-I2-P7-13.pdf
* https://www.bouncycastle.org/
* http://tutorials.jenkov.com/java-cryptography/cipher.html
......@@ -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
*