Commit 14d585da authored by calocedre TAC's avatar calocedre TAC
Browse files

Merge branch 'master' into feature/completetestjs

parents 60c7a2a3 7255e696
Pipeline #234000 failed with stages
in 7 minutes and 6 seconds
......@@ -2,11 +2,11 @@ image: maven:3.6-jdk-11
stages:
- build
- test
- deploy
- testjs
- buildjs
build:
build-java:
stage: build
tags:
- ci
......@@ -18,8 +18,26 @@ build:
paths:
- CLEA-lib/java/target/*.jar
test:
build-c:
stage: build
tags:
- ci
image: debian:latest
before_script:
- apt-get update
- apt-get install -y -qq cmake make gcc git
script:
- cd CLEA-lib/c
- mkdir build && cd build
- cmake ..
- make
artifacts:
paths:
- CLEA-lib/c/build/test_*
- CLEA-lib/c/build/build_clea
test-java:
stage: test
tags:
- ci
script:
......@@ -29,6 +47,18 @@ test:
paths:
- CLEA-lib/java/target/*.jar
test-interop:
stage: test
tags:
- ci
image: python:3-buster
before_script:
- apt-get update
- apt-get install -y -qq openjdk-11-jre
script:
- cd CLEA-lib/test
- python test_clea.py
deploy:
stage: deploy
tags:
......
......@@ -2,7 +2,7 @@
## Objectives
The QR code of a location/event, dynamic, which must be scanned at the entrance contains an URL ("deep link") structured by a prefix (for example for France: https://tac.gouv.fr/), followed by the 'location Specific Part' coded in base64. This directory gives an example of encoding in C language of the 'location Specific Part' of the QR code according to the [protocol Cléa](https://hal.inria.fr/hal-03146022).
The QR code of a location/event, dynamic, which must be scanned at the entrance contains an URL ("deep link") structured by a prefix (for example for France: https://tac.gouv.fr?v=0#), followed by the 'location Specific Part' coded in base64. This directory gives an example of encoding in C language of the 'location Specific Part' of the QR code according to the [protocol Cléa](https://hal.inria.fr/hal-03146022).
This Proof of Concept can be used as a basis for:
......
......@@ -84,11 +84,15 @@ int32_t clea_renew_qrcode(uint32_t *ptr_ct_periodStart, uint32_t *ptr_t_qrStart)
if (c->locContactMsgPresent)
{
loc_msg_start = cpt;
for (i = 0; i < sizeof(c->locationPhone); i++)
// Encode 56 first bits (7 bytes + 4 bits)
for (i = 0; i < sizeof(c->locationPhone) - 1; i++)
{
LSP[cpt++] = c->locationPhone[i];
}
// Encode the last 4 bits + 4 bits of padding
LSP[cpt++] = c->locationPhone[sizeof(c->locationPhone)-1] & 0xF0;
LSP[cpt++] = c->locationRegion & 0xFF;
for (i = 0; i < sizeof(c->locationPin); i++)
{
......@@ -160,7 +164,7 @@ static void compute_TLKey(void)
*/
static void to_base64(uint8_t *in, uint8_t *out, uint8_t n)
{
static const uint8_t base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const uint8_t base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
uint8_t *pos;
const uint8_t *end, *start;
......
......@@ -3,7 +3,7 @@
#include <stdint.h>
#define SK_L_SIZE (60)
#define SK_L_SIZE (51)
/* Permanent location secret key, this key is not defined in the clea library itself,
it should be defined outside as it depends on the hardware specific storage location */
......@@ -34,8 +34,9 @@ typedef struct
uint8_t periodDuration; // 8 bits: period duration in hours
// Location contact
uint8_t locationPhone[8]; // 4 bits per digit, pad with 0xF
uint8_t locationPin[4]; // 4 bits per digit
uint8_t locationPhone[8]; // 60 bits, 4 bits per digit, pad with 0xF (=> 15 digits max)
uint8_t locationRegion; // 8 bits: coarse grain geographical information for the location
uint8_t locationPin[3]; // 4 bits per digit (=> 6 digits)
} clea_conf_t;
extern clea_conf_t clea_conf;
......
......@@ -3,7 +3,7 @@
#include <stdlib.h>
#include "clea.h"
uint8_t SK_L[SK_L_SIZE] = {17, 50, 178, 117, 142, 93, 11, 228, 16, 198, 218, 172, 28, 203, 30, 149, 105, 157, 195, 247, 12, 226, 62, 13, 255, 126, 84, 96, 87, 163, 80, 97, 213, 211, 66, 20, 248, 127, 9, 64, 84, 127, 135, 165, 127, 171, 14, 78, 34, 229, 223, 249, 156, 59, 123, 51, 153, 17, 250, 106};
uint8_t SK_L[SK_L_SIZE] = {17, 50, 178, 117, 142, 93, 11, 228, 16, 198, 218, 172, 28, 203, 30, 149, 105, 157, 195, 247, 12, 226, 62, 13, 255, 126, 84, 96, 87, 163, 80, 97, 213, 211, 66, 20, 248, 127, 9, 64, 84, 127, 135, 165, 127, 171, 14, 78, 34, 229, 223};
uint8_t PK_SA[PUBLIC_KEY_SIZE] = {0xbc, 0x05, 0x51, 0x56, 0x7e, 0xcc, 0x32, 0x77, 0x99, 0x8f, 0x4b, 0xa9, 0xaf, 0x0c, 0xa6, 0x35, 0xdd, 0xe3, 0x6b, 0xd2, 0x01, 0x55, 0x95, 0xbc, 0xab, 0xa2, 0x74, 0x0c, 0xcd, 0xc0, 0x6e, 0x7f, 0x78, 0x0d, 0x9e, 0xd2, 0xf4, 0x7f, 0xbc, 0xc5, 0xb4, 0xb4, 0x65, 0x49, 0x73, 0x3e, 0x2f, 0x9f, 0xb0, 0xf5, 0xc5, 0x86, 0x7a, 0x08, 0xec, 0xf6, 0x45, 0x16, 0xf9, 0x8d, 0x4c, 0x8a, 0x7e, 0xd5};
uint8_t PK_MCTA[PUBLIC_KEY_SIZE] = {0xbc, 0x05, 0x51, 0x56, 0x7e, 0xcc, 0x32, 0x77, 0x99, 0x8f, 0x4b, 0xa9, 0xaf, 0x0c, 0xa6, 0x35, 0xdd, 0xe3, 0x6b, 0xd2, 0x01, 0x55, 0x95, 0xbc, 0xab, 0xa2, 0x74, 0x0c, 0xcd, 0xc0, 0x6e, 0x7f, 0x78, 0x0d, 0x9e, 0xd2, 0xf4, 0x7f, 0xbc, 0xc5, 0xb4, 0xb4, 0x65, 0x49, 0x73, 0x3e, 0x2f, 0x9f, 0xb0, 0xf5, 0xc5, 0x86, 0x7a, 0x08, 0xec, 0xf6, 0x45, 0x16, 0xf9, 0x8d, 0x4c, 0x8a, 0x7e, 0xd5};
......@@ -18,7 +18,8 @@ clea_conf_t clea_conf =
.countryCode = 250, // France numeric code as defined in ISO3166-1
.periodDuration = 3, // 3 hours
.locationPhone = {0x33, 0x80, 0x01, 0x30, 0x00, 0x0F, 0xFF, 0xFF}, // +33 800 130 000
.locationPin = {0xDE, 0xAD, 0xBE, 0xEF} // "DEADBEEF"
.locationRegion = 11,
.locationPin = {0xDE, 0xAD, 0xBE} // "DEADBE"
};
uint8_t LSP_base64[LSP_BASE64_SIZE];
......
......@@ -13,7 +13,7 @@
#include "external_deps/time.h"
#include "clea.h"
uint8_t SK_L[SK_L_SIZE] = {17, 50, 178, 117, 142, 93, 11, 228, 16, 198, 218, 172, 28, 203, 30, 149, 105, 157, 195, 247, 12, 226, 62, 13, 255, 126, 84, 96, 87, 163, 80, 97, 213, 211, 66, 20, 248, 127, 9, 64, 84, 127, 135, 165, 127, 171, 14, 78, 34, 229, 223, 249, 156, 59, 123, 51, 153, 17, 250, 106};
uint8_t SK_L[SK_L_SIZE] = {17, 50, 178, 117, 142, 93, 11, 228, 16, 198, 218, 172, 28, 203, 30, 149, 105, 157, 195, 247, 12, 226, 62, 13, 255, 126, 84, 96, 87, 163, 80, 97, 213, 211, 66, 20, 248, 127, 9, 64, 84, 127, 135, 165, 127, 171, 14, 78, 34, 229, 223};
uint8_t PK_HA[PUBLIC_KEY_SIZE] = {0xbc, 0x05, 0x51, 0x56, 0x7e, 0xcc, 0x32, 0x77, 0x99, 0x8f, 0x4b, 0xa9, 0xaf, 0x0c, 0xa6, 0x35, 0xdd, 0xe3, 0x6b, 0xd2, 0x01, 0x55, 0x95, 0xbc, 0xab, 0xa2, 0x74, 0x0c, 0xcd, 0xc0, 0x6e, 0x7f, 0x78, 0x0d, 0x9e, 0xd2, 0xf4, 0x7f, 0xbc, 0xc5, 0xb4, 0xb4, 0x65, 0x49, 0x73, 0x3e, 0x2f, 0x9f, 0xb0, 0xf5, 0xc5, 0x86, 0x7a, 0x08, 0xec, 0xf6, 0x45, 0x16, 0xf9, 0x8d, 0x4c, 0x8a, 0x7e, 0xd5};
uint8_t PK_MCTA[PUBLIC_KEY_SIZE] = {0xbc, 0x05, 0x51, 0x56, 0x7e, 0xcc, 0x32, 0x77, 0x99, 0x8f, 0x4b, 0xa9, 0xaf, 0x0c, 0xa6, 0x35, 0xdd, 0xe3, 0x6b, 0xd2, 0x01, 0x55, 0x95, 0xbc, 0xab, 0xa2, 0x74, 0x0c, 0xcd, 0xc0, 0x6e, 0x7f, 0x78, 0x0d, 0x9e, 0xd2, 0xf4, 0x7f, 0xbc, 0xc5, 0xb4, 0xb4, 0x65, 0x49, 0x73, 0x3e, 0x2f, 0x9f, 0xb0, 0xf5, 0xc5, 0x86, 0x7a, 0x08, 0xec, 0xf6, 0x45, 0x16, 0xf9, 0x8d, 0x4c, 0x8a, 0x7e, 0xd5};
......@@ -35,7 +35,7 @@ uint8_t LSP_base64[LSP_BASE64_SIZE];
void display_qrcode(int width, int height)
{
uint8_t content[20 + sizeof(LSP_base64)] = "http://tac.gouv.fr/";
uint8_t content[24 + sizeof(LSP_base64)] = "http://tac.gouv.fr?v=0#";
uint8_t qr[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok;
......
......@@ -32,7 +32,7 @@ void print_uuid(uint8_t uuid[16])
void usage(char *s, char *err)
{
printf("ERROR: %s\n\n", err);
printf("Usage: %s staff countryCode CRIexp venueType venueCategory1 venueCategory2 periodDuration PK_SA PK_MCTA SK_L [locationPhone locationPin]\n\n", s);
printf("Usage: %s staff countryCode CRIexp venueType venueCategory1 venueCategory2 periodDuration PK_SA PK_MCTA SK_L [locationPhone locationRegion locationPin]\n\n", s);
printf("locationPhone: 15-digit-max international phone number\n");
printf("locationPin: 8-digit-max pin code\n");
exit(1);
......@@ -49,10 +49,10 @@ int main(int argc, char *argv[])
uint32_t t_qrStart, ct_periodStart;
uint8_t LTId[16];
if ((argc == 13) || (argc == 11))
if ((argc == 14) || (argc == 11))
{
clea_conf.staff = atoi(argv[1]);
clea_conf.locContactMsgPresent = (argc == 13);
clea_conf.locContactMsgPresent = (argc == 14);
clea_conf.countryCode = atoi(argv[2]);
clea_conf.CRIexp = atoi(argv[3]);
clea_conf.venueType = atoi(argv[4]);
......@@ -70,7 +70,10 @@ int main(int argc, char *argv[])
{
USAGE("Too many digits in locationPhone");
}
if (parse_bcd(argv[12], clea_conf.locationPin, sizeof(clea_conf.locationPin)))
clea_conf.locationRegion = atoi(argv[12]);
if (parse_bcd(argv[13], clea_conf.locationPin, sizeof(clea_conf.locationPin)))
{
USAGE("Too many digits in locationPin");
}
......@@ -85,6 +88,7 @@ int main(int argc, char *argv[])
exit(r);
}
printf("=VALUES=");
print_qrcode();
print_uuid(LTId);
printf(" %lu %lu\n",ct_periodStart, t_qrStart);
......
......@@ -52,7 +52,7 @@ uint8_t parse_bcd(char *string, uint8_t *array, uint8_t size)
i++;
}
for(k = i / 2 + 1; k < size; k++)
for(k = i / 2 + i%2; k < size; k++)
{
array[k] = 0xFF;
}
......
......@@ -2,7 +2,7 @@
## Objectives
The QR code of a location/event, dynamic, which must be scanned at the entrance contains an URL ("deep link") structured by a prefix (for example for France: https://tac.gouv.fr/), followed by the 'location Specific Part' coded in base64. This directory gives an example of encoding in Java language of the 'location Specific Part' of the QR code according to the [protocol Cléa](https://hal.inria.fr/hal-03146022).
The QR code of a location/event, dynamic, which must be scanned at the entrance contains an URL ("deep link") structured by a prefix (for example for France: https://tac.gouv.fr?v=0#), followed by the 'location Specific Part' coded in base64. This directory gives an example of encoding in Java language of the 'location Specific Part' of the QR code according to the [protocol Cléa](https://hal.inria.fr/hal-03146022).
This Proof of Concept can be used as a basis for:
......
......@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>fr.inria.clea</groupId>
<artifactId>clea-crypto</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>0.0.2-SNAPSHOT</version>
<dependencies>
<dependency>
......@@ -22,11 +22,23 @@
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.68</version>
</dependency>
<!-- Bean validation -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.13.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
</dependency>
<!-- end Bean validation -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
......
......@@ -20,6 +20,7 @@ import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.time.Instant;
import java.util.Arrays;
import java.util.UUID;
......@@ -44,6 +45,10 @@ import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;
import fr.inria.clea.lsp.exception.CleaEncryptionException;
import fr.inria.clea.lsp.utils.TimeUtils;
import lombok.extern.slf4j.Slf4j;
/**
* Encryption/Decription respecting ECIES-KEM (Elliptic Curve Integrated
* Encryption Scheme with Key encapsulation mechanisms )
......@@ -56,6 +61,7 @@ import org.bouncycastle.util.encoders.Hex;
* for Public-Key Encryption”, 2006</a>
*
*/
@Slf4j
public class CleaEciesEncoder {
/* Type of the elliptic curve */
......@@ -249,65 +255,6 @@ public class CleaEciesEncoder {
return out;
}
/**
* concat two bytes array in one
*
* @param part1 first bytes array
* @param part2 second bytes array
* @return bytes array concatenation
*/
protected byte[] concat(byte[] part1, byte[] part2) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(part1);
outputStream.write(part2);
byte concatParts[] = outputStream.toByteArray();
return concatParts;
}
/**
* convert 32 bytes array in UUID format
*
* @param bytes 32 bytes array
* @return UUID
*/
protected UUID bytesToUuid(byte[] bytes) {
ByteBuffer bb = ByteBuffer.wrap(bytes);
long firstLong = bb.getLong();
long secondLong = bb.getLong();
return new UUID(firstLong, secondLong);
}
/**
* convert a UUID format in 32 bytes array
*
* @param uuid UUID
* @return 32 bytes array
*/
protected byte[] uuidToBytes(UUID uuid) {
ByteBuffer buffer = ByteBuffer.wrap(new byte[16]);
buffer.putLong(uuid.getMostSignificantBits());
buffer.putLong(uuid.getLeastSignificantBits());
return buffer.array();
}
/**
* convert an int in 32 bytes array
*
* @param data int to be converted
* @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) };
}
/**
* Compute the LTKey (Temporary Location Key) respecting Cléa protocol
* LTKey(t_periodStart) = SHA256(SK_L | t_periodStart)
......@@ -318,9 +265,10 @@ public class CleaEciesEncoder {
* @return LTKey (Temporary Location Key)
* @throws CleaEncryptionException
*/
public byte[] computeLocationTemporarySecretKey(String permanentLocationSecretKey, int periodStartTime) throws CleaEncryptionException {
public byte[] computeLocationTemporarySecretKey(String permanentLocationSecretKey, Instant periodStartTime) throws CleaEncryptionException {
log.info("permanentLocationSecretKey: {}, periodStartTime= {}", permanentLocationSecretKey, periodStartTime);
try {
byte[] concatKey = this.concat(intToBytes(periodStartTime), Hex.decode(permanentLocationSecretKey));
byte[] concatKey = this.concat(instantToBytes(periodStartTime), Hex.decode(permanentLocationSecretKey));
MessageDigest msg = MessageDigest.getInstance("SHA-256");
byte[] locationTemporarySecretKey = msg.digest(concatKey);
......@@ -359,4 +307,68 @@ public class CleaEciesEncoder {
}
}
private byte[] instantToBytes(Instant periodStartTime) {
long timestamp = TimeUtils.ntpTimestampFromInstant(periodStartTime);
return intToBytes((int) timestamp);
}
/**
* convert an int in 32 bytes array
*
* @param data int to be converted
* @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) };
}
/**
* concat two bytes array in one
*
* @param part1 first bytes array
* @param part2 second bytes array
* @return bytes array concatenation
*/
protected byte[] concat(byte[] part1, byte[] part2) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(part1);
outputStream.write(part2);
byte concatParts[] = outputStream.toByteArray();
return concatParts;
}
/**
* convert 32 bytes array in UUID format
*
* @param bytes 32 bytes array
* @return UUID
*/
protected UUID bytesToUuid(byte[] bytes) {
ByteBuffer bb = ByteBuffer.wrap(bytes);
long firstLong = bb.getLong();
long secondLong = bb.getLong();
return new UUID(firstLong, secondLong);
}
/**
* convert a UUID format in 32 bytes array
*
* @param uuid UUID
* @return 32 bytes array
*/
protected byte[] uuidToBytes(UUID uuid) {
ByteBuffer buffer = ByteBuffer.wrap(new byte[16]);
buffer.putLong(uuid.getMostSignificantBits());
buffer.putLong(uuid.getLeastSignificantBits());
return buffer.array();
}
}
......@@ -9,6 +9,8 @@ import javax.validation.constraints.Max;
import org.bouncycastle.util.Arrays;
import fr.inria.clea.lsp.exception.CleaEncodingException;
import fr.inria.clea.lsp.exception.CleaEncryptionException;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
......
package fr.inria.clea.lsp;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.Objects;
import java.util.UUID;
import fr.devnied.bitlib.BytesUtils;
import fr.inria.clea.lsp.utils.TimeUtils;
import fr.inria.clea.lsp.exception.CleaCryptoException;
import fr.inria.clea.lsp.exception.CleaEncryptionException;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
......@@ -13,7 +16,7 @@ import lombok.extern.slf4j.Slf4j;
@Builder
@Slf4j
public class Location {
public static final String COUNTRY_SPECIFIC_PREFIX = "https://tac.gouv.fr/";
public static final String COUNTRY_SPECIFIC_PREFIX = "https://tac.gouv.fr?v=0#";
private String permanentLocationSecretKey;
private String serverAuthorityPublicKey;
private String manualContactTracingAuthorityPublicKey;
......@@ -31,8 +34,8 @@ public class Location {
* @return the deep link as a String
* @throws CleaEncryptionException
*/
public String newDeepLink() throws CleaEncryptionException {
int periodStartTime = TimeUtils.hourRoundedCurrentTimeTimestamp32();
public String newDeepLink() throws CleaCryptoException {
Instant periodStartTime = Instant.now().truncatedTo(ChronoUnit.HOURS);
return this.newDeepLink(periodStartTime);
}
......@@ -41,14 +44,11 @@ public class Location {
* at the given period start time with a QR code validaty
* starting at the period start time.
*
* @param periodStartTime Starting time of the period, expressed as the number
* of seconds since January 1st, 1900 (NTP timestamp limited to the 32-bit
* seconds field), by convention in the UTC (Coordinated Universal Time) timezone.
* A period necessarily starts at a round hour.
* @param periodStartTime Starting time of the period. A period necessarily starts at a round hour.
* @return the deep link as a String
* @throws CleaEncryptionException
*/
public String newDeepLink(int periodStartTime) throws CleaEncryptionException {
public String newDeepLink(Instant periodStartTime) throws CleaCryptoException {
// QR-code validity starts at period start time
return this.newDeepLink(periodStartTime, periodStartTime);
}
......@@ -58,18 +58,12 @@ public class Location {
* at the given period start time with a QR code validaty
* starting at the period start time.
*
* @param periodStartTime Starting time of the period, expressed as the number
* of seconds since January 1st, 1900 (NTP timestamp limited to the 32-bit
* seconds field), by convention in the UTC (Coordinated Universal Time) timezone.
* A period necessarily starts at a round hour.
* @param qrCodeValidityStartTime Starting time of the QR code validity timespan,
* expressed as the number of seconds since January 1st, 1900 (NTP timestamp
* limited to the 32-bit seconds field),
* by convention in UTC (Coordinated Universal Time) timezone.
* @param periodStartTime Starting time of the period. A period necessarily starts at a round hour.
* @param qrCodeValidityStartTime Starting time of the QR code validity timespan.
* @return the deep link as a String
* @throws CleaEncryptionException
*/
public String newDeepLink(int periodStartTime, int qrCodeValidityStartTime) throws CleaEncryptionException {
public String newDeepLink(Instant periodStartTime, Instant qrCodeValidityStartTime) throws CleaCryptoException {
this.setPeriodStartTime(periodStartTime);
this.setQrCodeValidityStartTime(periodStartTime, qrCodeValidityStartTime);
return COUNTRY_SPECIFIC_PREFIX + this.getLocationSpecificPartEncryptedBase64();
......@@ -80,22 +74,22 @@ public class Location {
* @return the base 64 encoded location specific part
* @throws CleaEncryptionException
*/
public String getLocationSpecificPartEncryptedBase64() throws CleaEncryptionException {
return Base64.getEncoder().encodeToString(this.getLocationSpecificPartEncrypted());
public String getLocationSpecificPartEncryptedBase64() throws CleaCryptoException {
return Base64.getUrlEncoder().encodeToString(this.getLocationSpecificPartEncrypted());
}
protected byte[] getLocationSpecificPartEncrypted() throws CleaEncryptionException {
protected byte[] getLocationSpecificPartEncrypted() throws CleaCryptoException {
if (Objects.nonNull(this.contact)) {
this.locationSpecificPart.setEncryptedLocationContactMessage(this.getLocationContactMessageEncrypted());
}
return new LocationSpecificPartEncoder(this.serverAuthorityPublicKey).encode(locationSpecificPart);
}
protected byte[] getLocationContactMessageEncrypted() throws CleaEncryptionException {
protected byte[] getLocationContactMessageEncrypted() throws CleaCryptoException {
return new LocationContactMessageEncoder(this.manualContactTracingAuthorityPublicKey).encode(contact);
}
protected void setPeriodStartTime(int periodStartTime) throws CleaEncryptionException {
protected void setPeriodStartTime(Instant periodStartTime) throws CleaEncryptionException {
byte[] locationTemporarySecretKey = this.getCleaEncoder().computeLocationTemporarySecretKey(this.permanentLocationSecretKey, periodStartTime);
UUID currentLocationTemporaryPublicId = this.getCleaEncoder().computeLocationTemporaryPublicId(locationTemporarySecretKey);
this.locationSpecificPart.setPeriodStartTime(periodStartTime);
......@@ -104,32 +98,32 @@ public class Location {
if (Objects.nonNull(this.contact)) {
this.contact.setPeriodStartTime(periodStartTime);
}
log.debug("new periodStartTime: {} ", Integer.toUnsignedString(periodStartTime));
log.debug("new periodStartTime: {} ", periodStartTime);
log.debug("locationTemporarySecretKey*: {}*", BytesUtils.bytesToString(locationTemporarySecretKey));
log.debug("locationTemporaryPublicID: " + currentLocationTemporaryPublicId.toString());
}
protected void setQrCodeValidityStartTime(int periodStartTime, int qrCodeValidityStartTime) {
protected void setQrCodeValidityStartTime(Instant periodStartTime, Instant qrCodeValidityStartTime) {
if ((this.locationSpecificPart.getQrCodeRenewalInterval() == 0)
&& (this.locationSpecificPart.getQrCodeValidityStartTime() != 0)) {
&& Objects.nonNull(this.locationSpecificPart.getQrCodeValidityStartTime())) {
log.warn("Cannot update QrCode validity start time. No renewal specified!");
return;
}
if(qrCodeValidityStartTime < periodStartTime){
if (qrCodeValidityStartTime.isBefore(periodStartTime)) {
log.warn("Cannot set QrCode validity start time to {}. It preceeds period validity (start: {}, duration (in hours): {}",
qrCodeValidityStartTime, periodStartTime, this.locationSpecificPart.getPeriodDuration());
return;
}
if (qrCodeValidityStartTime > periodStartTime + this.locationSpecificPart.getPeriodDuration() * TimeUtils.NB_SECONDS_PER_HOUR) {
if (qrCodeValidityStartTime.isAfter(periodStartTime.plus(this.locationSpecificPart.getPeriodDuration(), ChronoUnit.HOURS))) {
log.warn("Cannot set QrCode validity start time to {}. It exceeds period validity (start: {}, duration (in hours): {}",
qrCodeValidityStartTime, periodStartTime, this.locationSpecificPart.getPeriodDuration());
return;
}
if ((this.locationSpecificPart.getQrCodeRenewalInterval() != 0) &&
(((qrCodeValidityStartTime - periodStartTime) % this.locationSpecificPart.getQrCodeRenewalInterval()) != 0)) {
(((qrCodeValidityStartTime.getEpochSecond() - periodStartTime.getEpochSecond()) % this.locationSpecificPart.getQrCodeRenewalInterval()) != 0)) {
log.warn("Cannot set QrCode validity start time to {}. It is not a multiple of qrCodeRenewalInterval (qrCodeValidityStartTime: {}, periodStartTime: {}, qrCodeRenewalInterval: {}",
qrCodeValidityStartTime, periodStartTime, this.locationSpecificPart.getQrCodeRenewalInterval());
return;
......