-
Notifications
You must be signed in to change notification settings - Fork 22
/
EciesUtils.java
153 lines (143 loc) · 6.12 KB
/
EciesUtils.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* PowerAuth Crypto Library
* Copyright 2023 Wultra s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.getlime.security.powerauth.crypto.lib.util;
import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.exception.EciesException;
import io.getlime.security.powerauth.crypto.lib.encryptor.model.EncryptorScope;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
/**
* A utility class for handling ECIES data.
*
* @author Roman Strobl, [email protected]
*/
public final class EciesUtils {
/**
* Private constructor.
*/
private EciesUtils() {
}
/**
* Generate MAC data for ECIES request or response MAC validation.
*
* @param sharedInfo2 Parameter sharedInfo2 for ECIES.
* @param encryptedData Encrypted data
* @return Resolved MAC data.
*/
public static byte[] generateMacData(final byte[] sharedInfo2, final byte[] encryptedData) {
return ByteUtils.concat(encryptedData, sharedInfo2);
}
/**
* Generate timestamp for ECIES request/response.
*
* @return Timestamp bytes to use for ECIES encryption.
*/
public static long generateTimestamp() {
// Protocol V3.2+
return System.currentTimeMillis();
}
/**
* Derive associated data for ECIES.
* @param scope Encryptor's scope.
* @param protocolVersion Protocol version.
* @param applicationKey Application key.
* @param activationId Activation ID.
* @return Derived associated data.
* @throws EciesException In case that activation ID is required but is missing.
*/
public static byte[] deriveAssociatedData(EncryptorScope scope, String protocolVersion, String applicationKey, String activationId) throws EciesException {
if (protocolVersion == null) {
throw new EciesException("Protocol version is missing");
}
if ("3.2".equals(protocolVersion)) {
if (applicationKey == null) {
throw new EciesException("Application key is missing");
}
if (scope == EncryptorScope.ACTIVATION_SCOPE) {
if (activationId == null) {
throw new EciesException("Activation ID is missing in ACTIVATION_SCOPE");
}
return ByteUtils.concatStrings(protocolVersion, applicationKey, activationId);
} else {
return ByteUtils.concatStrings(protocolVersion, applicationKey);
}
} else {
return null;
}
}
/**
* Derive base for SharedInfo2 calculation for ECIES encryption scheme.
* @param scope Scope of the encryptor.
* @param applicationSecret Application's secret.
* @param transportKey Transport key, required when scope is {@link EncryptorScope#ACTIVATION_SCOPE}.
* @return Bytes representing SharedInfo2 base.
* @throws EciesException In case of some required parameter is missing or if underlying cryptographic primitive fail.
*/
public static byte[] deriveSharedInfo2Base(EncryptorScope scope, String applicationSecret, byte[] transportKey) throws EciesException {
if (applicationSecret == null) {
throw new EciesException("Missing applicationSecret parameter");
}
final byte[] applicationSecretBytes = applicationSecret.getBytes(StandardCharsets.UTF_8);
if (scope == EncryptorScope.APPLICATION_SCOPE) {
// Application scope
return Hash.sha256(applicationSecretBytes);
} else {
// Activation scope
if (transportKey == null || transportKey.length != 16) {
throw new EciesException("Invalid or missing transportKey");
}
try {
return new HMACHashUtilities().hash(transportKey, applicationSecretBytes);
} catch (Exception e) {
throw new EciesException("HMAC calculation failed", e);
}
}
}
/**
* Derive final SharedInfo2 constant for ECIES encryption scheme.
* @param protocolVersion Protocol's version.
* @param sharedInfo2Base SharedInfo2 base, calculated by {@link #deriveSharedInfo2Base(EncryptorScope, String, byte[])} function.
* @param ephemeralPublicKey Ephemeral public key. Value is null for response encryption / decryption.
* @param nonce Nonce for request or response.
* @param timestamp Timestamp for request or response.
* @param associatedData Associated data.
* @return Bytes representing SharedInfo2 parameter for ECIES encryption.
* @throws EciesException In case that some required parameter is missing.
*/
public static byte[] deriveSharedInfo2(String protocolVersion, byte[] sharedInfo2Base, byte[] ephemeralPublicKey, byte[] nonce, Long timestamp, byte[] associatedData) throws EciesException {
if (sharedInfo2Base == null) {
throw new EciesException("Missing sharedInfo2Base parameter");
}
if ("3.2".equals(protocolVersion)) {
if (nonce == null) {
throw new EciesException("Missing nonce parameter");
}
if (timestamp == null) {
throw new EciesException("Missing timestamp parameter");
}
if (associatedData == null) {
throw new EciesException("Missing associatedData parameter");
}
return ByteUtils.concatWithSizes(
sharedInfo2Base,
nonce,
ByteBuffer.allocate(Long.BYTES).putLong(timestamp).array(),
ephemeralPublicKey,
associatedData);
}
return sharedInfo2Base;
}
}