• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hyperwallet / java-sdk / #632

26 Apr 2024 09:51PM CUT coverage: 97.031%. Remained the same
#632

push

akalichety-hw
LI-36725 -Version bumup for Java_jason

5555 of 5725 relevant lines covered (97.03%)

67.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.54
/src/main/java/com/hyperwallet/clientsdk/util/HyperwalletEncryption.java
1
package com.hyperwallet.clientsdk.util;
2

3
import com.hyperwallet.clientsdk.HyperwalletException;
4
import com.nimbusds.jose.Algorithm;
5
import com.nimbusds.jose.EncryptionMethod;
6
import com.nimbusds.jose.JOSEException;
7
import com.nimbusds.jose.JWEAlgorithm;
8
import com.nimbusds.jose.JWEDecrypter;
9
import com.nimbusds.jose.JWEEncrypter;
10
import com.nimbusds.jose.JWEHeader;
11
import com.nimbusds.jose.JWEObject;
12
import com.nimbusds.jose.JWSAlgorithm;
13
import com.nimbusds.jose.JWSHeader;
14
import com.nimbusds.jose.JWSObject;
15
import com.nimbusds.jose.JWSSigner;
16
import com.nimbusds.jose.JWSVerifier;
17
import com.nimbusds.jose.Payload;
18
import com.nimbusds.jose.crypto.ECDHDecrypter;
19
import com.nimbusds.jose.crypto.ECDHEncrypter;
20
import com.nimbusds.jose.crypto.ECDSASigner;
21
import com.nimbusds.jose.crypto.ECDSAVerifier;
22
import com.nimbusds.jose.crypto.RSADecrypter;
23
import com.nimbusds.jose.crypto.RSAEncrypter;
24
import com.nimbusds.jose.crypto.RSASSASigner;
25
import com.nimbusds.jose.crypto.RSASSAVerifier;
26
import com.nimbusds.jose.jwk.ECKey;
27
import com.nimbusds.jose.jwk.JWK;
28
import com.nimbusds.jose.jwk.JWKSet;
29
import com.nimbusds.jose.jwk.KeyType;
30
import com.nimbusds.jose.jwk.RSAKey;
31

32

33
import java.io.File;
34
import java.io.IOException;
35
import java.net.*;
36
import java.nio.file.Files;
37
import java.nio.file.Paths;
38
import java.text.ParseException;
39
import java.util.Arrays;
40
import java.util.Collections;
41
import java.util.Date;
42
import java.util.HashSet;
43
import java.util.List;
44

45
public class HyperwalletEncryption {
46

47
    private static final String EXPIRATION = "exp";
48
    private static final Integer MILLISECONDS_IN_ONE_MINUTE = 60000;
1✔
49
    private static final Long MILLISECONDS_IN_SECOND = 1000L;
1✔
50
    private static final Integer EXPIRATION_MINUTES = 5;
1✔
51
    private static final JWEAlgorithm ENCRYPTION_ALGORITHM = JWEAlgorithm.RSA_OAEP_256;
1✔
52
    private static final JWSAlgorithm SIGN_ALGORITHM = JWSAlgorithm.RS256;
1✔
53
    private static final EncryptionMethod ENCRYPTION_METHOD = EncryptionMethod.A256CBC_HS512;
1✔
54
    private static final String INVALID_KEY_TYPE_STRING = "'kty' not supported = %s";
55

56
    private static final List<JWEAlgorithm> SUPPORTED_JWE_ALGORITHMS = Arrays.asList(JWEAlgorithm.RSA_OAEP_256,
1✔
57
            JWEAlgorithm.ECDH_ES,
58
            JWEAlgorithm.ECDH_ES_A128KW,
59
            JWEAlgorithm.ECDH_ES_A192KW,
60
            JWEAlgorithm.ECDH_ES_A256KW);
61
    private static final List<JWSAlgorithm> SUPPORTED_JWS_ALGORITHMS = Arrays.asList(JWSAlgorithm.RS256,
1✔
62
            JWSAlgorithm.RS384,
63
            JWSAlgorithm.RS512,
64
            JWSAlgorithm.PS256,
65
            JWSAlgorithm.PS384,
66
            JWSAlgorithm.PS512,
67
            JWSAlgorithm.ES256,
68
            JWSAlgorithm.ES384,
69
            JWSAlgorithm.ES512);
70
    private static final List<EncryptionMethod> SUPPORTED_ENCRYPTION_METHODS = Arrays.asList(EncryptionMethod.A128CBC_HS256,
1✔
71
            EncryptionMethod.A192CBC_HS384,
72
            EncryptionMethod.A256CBC_HS512,
73
            EncryptionMethod.A128GCM,
74
            EncryptionMethod.A256GCM);
75

76
    private final JWEAlgorithm encryptionAlgorithm;
77
    private final JWSAlgorithm signAlgorithm;
78
    private final EncryptionMethod encryptionMethod;
79
    private final String clientPrivateKeySetLocation;
80
    private final String hyperwalletKeySetLocation;
81
    private final Integer jwsExpirationMinutes;
82

83
    private Proxy proxy;
84
    private String proxyUsername;
85
    private String proxyPassword;
86

87
    public HyperwalletEncryption(JWEAlgorithm encryptionAlgorithm, JWSAlgorithm signAlgorithm, EncryptionMethod encryptionMethod,
88
            String clientPrivateKeySetLocation, String hyperwalletKeySetLocation, Integer jwsExpirationMinutes) {
129✔
89
        this.encryptionAlgorithm = encryptionAlgorithm == null ? ENCRYPTION_ALGORITHM : encryptionAlgorithm;
129✔
90
        this.signAlgorithm = signAlgorithm == null ? SIGN_ALGORITHM : signAlgorithm;
129✔
91
        this.encryptionMethod = encryptionMethod == null ? ENCRYPTION_METHOD : encryptionMethod;
129✔
92
        this.clientPrivateKeySetLocation = clientPrivateKeySetLocation;
129✔
93
        this.hyperwalletKeySetLocation = hyperwalletKeySetLocation;
129✔
94
        this.jwsExpirationMinutes = jwsExpirationMinutes == null ? EXPIRATION_MINUTES : jwsExpirationMinutes;
129✔
95

96
        if (!SUPPORTED_JWS_ALGORITHMS.contains(this.signAlgorithm)) {
129✔
97
            throw new IllegalArgumentException("Unsupported signing algorithm " + this.signAlgorithm);
1✔
98
        }
99
        if (!SUPPORTED_JWE_ALGORITHMS.contains(this.encryptionAlgorithm)) {
128✔
100
            throw new IllegalArgumentException("Unsupported encryption algorithm " + this.encryptionAlgorithm);
1✔
101
        }
102
        if (!SUPPORTED_ENCRYPTION_METHODS.contains(this.encryptionMethod)) {
127✔
103
            throw new IllegalArgumentException("Unsupported encryption method " + this.encryptionMethod);
2✔
104
        }
105
    }
125✔
106

107
    public String encrypt(String body) throws JOSEException, IOException, ParseException {
108

109
        JWK clientPrivateKey = getKeyByAlgorithm(loadKeySet(clientPrivateKeySetLocation), signAlgorithm);
22✔
110
        JWK hyperwalletPublicKey = getKeyByAlgorithm(loadKeySet(hyperwalletKeySetLocation), encryptionAlgorithm);
21✔
111
        JWSSigner jwsSigner = getJWSSigner(clientPrivateKey);
20✔
112
        JWEEncrypter jweEncrypter = getJWEEncrypter(hyperwalletPublicKey);
20✔
113

114
        JWSObject jwsObject = new JWSObject(
19✔
115
                new JWSHeader.Builder(signAlgorithm)
116
                        .keyID(clientPrivateKey.getKeyID())
19✔
117
                        .criticalParams(new HashSet<>(Collections.singletonList(EXPIRATION)))
19✔
118
                        .customParam(EXPIRATION, getJWSExpirationMillis()).build(),
19✔
119
                new Payload(body));
120

121
        jwsObject.sign(jwsSigner);
19✔
122

123
        JWEObject jweObject = new JWEObject(
19✔
124
                new JWEHeader.Builder(encryptionAlgorithm, encryptionMethod)
125
                        .keyID(hyperwalletPublicKey.getKeyID()).build(),
19✔
126
                new Payload(jwsObject));
127

128
        jweObject.encrypt(jweEncrypter);
19✔
129

130
        return jweObject.serialize();
19✔
131
    }
132

133
    public String decrypt(String body) throws ParseException, IOException, JOSEException {
134

135
        JWK privateKeyToDecrypt = getKeyByAlgorithm(loadKeySet(clientPrivateKeySetLocation), encryptionAlgorithm);
12✔
136
        JWK publicKeyToSign = getKeyByAlgorithm(loadKeySet(hyperwalletKeySetLocation), signAlgorithm);
12✔
137
        JWEDecrypter jweDecrypter = getJWEDecrypter(privateKeyToDecrypt);
12✔
138
        JWSVerifier jwsVerifier = getJWSVerifier(publicKeyToSign);
12✔
139

140
        JWEObject jweObject = JWEObject.parse(body);
12✔
141
        jweObject.decrypt(jweDecrypter);
12✔
142
        JWSObject jwsObject = jweObject.getPayload().toJWSObject();
11✔
143
        verifySignatureExpirationDate(jwsObject.getHeader().getCustomParam(EXPIRATION));
11✔
144
        boolean verifyStatus = jwsObject.verify(jwsVerifier);
11✔
145
        if (!verifyStatus) {
11✔
146
            throw new HyperwalletException("JWS signature is incorrect");
×
147
        }
148
        return jwsObject.getPayload().toString();
11✔
149
    }
150

151
    public void verifySignatureExpirationDate(Object signatureExpirationDate) {
152
        if (signatureExpirationDate == null) {
14✔
153
            throw new HyperwalletException("exp JWS header param was null");
1✔
154
        }
155
        if (!(signatureExpirationDate instanceof Long)) {
13✔
156
            throw new HyperwalletException("exp JWS header must be of type Long");
1✔
157
        }
158
        long expirationTimeSeconds = (long) signatureExpirationDate;
12✔
159
        if (new Date().getTime() / MILLISECONDS_IN_SECOND > expirationTimeSeconds) {
12✔
160
            throw new HyperwalletException("Response message signature(JWS) has expired");
1✔
161
        }
162
    }
11✔
163

164
    public JWEAlgorithm getEncryptionAlgorithm() {
165
        return encryptionAlgorithm;
3✔
166
    }
167

168
    public JWSAlgorithm getSignAlgorithm() {
169
        return signAlgorithm;
3✔
170
    }
171

172
    public EncryptionMethod getEncryptionMethod() {
173
        return encryptionMethod;
3✔
174
    }
175

176
    public String getClientPrivateKeySetLocation() {
177
        return clientPrivateKeySetLocation;
3✔
178
    }
179

180
    public String getHyperwalletKeySetLocation() {
181
        return hyperwalletKeySetLocation;
3✔
182
    }
183

184
    public Integer getJwsExpirationMinutes() {
185
        return jwsExpirationMinutes;
3✔
186
    }
187

188
    private JWKSet loadKeySet(String keySetLocation) throws IOException, ParseException {
189
        URL url;
190
        try {
191
            url = new URL(keySetLocation);
67✔
192
        } catch (MalformedURLException e) {
65✔
193
            checkKeySetLocationIsFile(keySetLocation);
65✔
194
            return JWKSet.load(new File(keySetLocation));
64✔
195
        }
2✔
196

197
        if (usesProxy()) {
2✔
198
            if (proxyUsername != null && proxyPassword != null) {
×
199
                Authenticator authenticator = new Request.DefaultPasswordAuthenticator(
×
200
                        proxyUsername, proxyPassword);
201
                Authenticator.setDefault(authenticator);
×
202
            }
203
            return JWKSet.load(url, 0, 0, 0, getProxy());
×
204
        }
205
        return JWKSet.load(url);
2✔
206
    }
207

208
    private long getJWSExpirationMillis() {
209
        return new Date(new Date().getTime() + MILLISECONDS_IN_ONE_MINUTE * jwsExpirationMinutes).getTime() / MILLISECONDS_IN_SECOND;
19✔
210
    }
211

212
    private <T extends Algorithm> JWK getKeyByAlgorithm(JWKSet keySet, T algorithm) {
213
        for (JWK key : keySet.getKeys()) {
66✔
214
            if (key.getAlgorithm().equals(algorithm)) {
108✔
215
                return key;
65✔
216
            }
217
        }
43✔
218
        throw new IllegalStateException("Algorithm = " + algorithm + " is not found in client or Hyperwallet key set");
1✔
219
    }
220

221
    private void checkKeySetLocationIsFile(String keySetLocation) {
222
        if (Files.notExists(Paths.get(keySetLocation))) {
65✔
223
            throw new IllegalArgumentException("Wrong client JWK set location");
1✔
224
        }
225
    }
64✔
226

227
    private JWSSigner getJWSSigner(JWK jwk) {
228
        try {
229
            KeyType kty = jwk.getKeyType();
20✔
230
            if (kty.equals(KeyType.RSA)) {
20✔
231
                return new RSASSASigner((RSAKey) jwk);
18✔
232
            } else if (kty.equals(KeyType.EC)) {
2✔
233
                return new ECDSASigner((ECKey) jwk);
2✔
234
            } else {
235
                throw new IllegalArgumentException(String.format(INVALID_KEY_TYPE_STRING, kty));
×
236
            }
237
        } catch (JOSEException e) {
×
238
            throw new HyperwalletException("Unable to create signer");
×
239
        }
240
    }
241

242
    private JWEEncrypter getJWEEncrypter(JWK jwk) {
243
        try {
244
            KeyType kty = jwk.getKeyType();
20✔
245
            if (kty.equals(KeyType.RSA)) {
20✔
246
                return new RSAEncrypter((RSAKey) jwk);
18✔
247
            } else if (kty.equals(KeyType.EC)) {
2✔
248
                return new ECDHEncrypter((ECKey) jwk);
1✔
249
            } else {
250
                throw new IllegalArgumentException(String.format(INVALID_KEY_TYPE_STRING, kty));
1✔
251
            }
252
        } catch (JOSEException e) {
×
253
            throw new HyperwalletException("Unable to create encrypter");
×
254
        }
255
    }
256

257
    private JWSVerifier getJWSVerifier(JWK jwk) {
258
        try {
259
            KeyType kty = jwk.getKeyType();
12✔
260
            if (kty.equals(KeyType.RSA)) {
12✔
261
                return new RSASSAVerifier(((RSAKey) jwk).toRSAPublicKey(), new HashSet<>(Collections.singletonList(EXPIRATION)));
11✔
262
            } else if (kty.equals(KeyType.EC)) {
1✔
263
                return new ECDSAVerifier(((ECKey) jwk).toECPublicKey(), new HashSet<>(Collections.singletonList(EXPIRATION)));
1✔
264
            } else {
265
                throw new IllegalArgumentException(String.format(INVALID_KEY_TYPE_STRING, kty));
×
266
            }
267
        } catch (JOSEException e) {
×
268
            throw new HyperwalletException("Unable to create verifier");
×
269
        }
270
    }
271

272
    private JWEDecrypter getJWEDecrypter(JWK jwk) {
273
        try {
274
            KeyType kty = jwk.getKeyType();
12✔
275
            if (kty.equals(KeyType.RSA)) {
12✔
276
                return new RSADecrypter((RSAKey) jwk);
11✔
277
            } else if (kty.equals(KeyType.EC)) {
1✔
278
                return new ECDHDecrypter((ECKey) jwk);
1✔
279
            } else {
280
                throw new IllegalArgumentException(String.format(INVALID_KEY_TYPE_STRING, kty));
×
281
            }
282
        } catch (JOSEException e) {
×
283
            throw new HyperwalletException("Unable to create decrypter");
×
284
        }
285
    }
286

287
    public Boolean usesProxy() {
288
        return proxy != null;
2✔
289
    }
290

291
    public void setProxy(String url, Integer port) {
292
        this.proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(url, port));
9✔
293
    }
9✔
294

295
    public void setProxy(Proxy proxy) {
296
        this.proxy = proxy;
1✔
297
    }
1✔
298

299
    public Proxy getProxy() {
300
        return proxy;
3✔
301
    }
302

303
    public String getProxyUsername() {
304
        return proxyUsername;
3✔
305
    }
306

307
    public void setProxyUsername(String proxyUsername) {
308
        this.proxyUsername = proxyUsername;
10✔
309
    }
10✔
310

311
    public String getProxyPassword() {
312
        return proxyPassword;
3✔
313
    }
314

315
    public void setProxyPassword(String proxyPassword) {
316
        this.proxyPassword = proxyPassword;
10✔
317
    }
10✔
318

319
    public static class HyperwalletEncryptionBuilder {
120✔
320

321
        private JWEAlgorithm encryptionAlgorithm;
322
        private JWSAlgorithm signAlgorithm;
323
        private EncryptionMethod encryptionMethod;
324
        private String clientPrivateKeySetLocation;
325
        private String hyperwalletKeySetLocation;
326
        private Integer jwsExpirationMinutes;
327

328
        private Proxy proxy;
329
        private String proxyUsername;
330
        private String proxyPassword;
331

332
        public HyperwalletEncryptionBuilder encryptionAlgorithm(JWEAlgorithm encryptionAlgorithm) {
333
            this.encryptionAlgorithm = encryptionAlgorithm;
82✔
334
            return this;
82✔
335
        }
336

337
        public HyperwalletEncryptionBuilder signAlgorithm(JWSAlgorithm signAlgorithm) {
338
            this.signAlgorithm = signAlgorithm;
81✔
339
            return this;
81✔
340
        }
341

342
        public HyperwalletEncryptionBuilder encryptionMethod(EncryptionMethod encryptionMethod) {
343
            this.encryptionMethod = encryptionMethod;
80✔
344
            return this;
80✔
345
        }
346

347
        public HyperwalletEncryptionBuilder clientPrivateKeySetLocation(String clientPrivateKeySetLocation) {
348
            this.clientPrivateKeySetLocation = clientPrivateKeySetLocation;
113✔
349
            return this;
113✔
350
        }
351

352
        public HyperwalletEncryptionBuilder hyperwalletKeySetLocation(String hyperwalletKeySetLocation) {
353
            this.hyperwalletKeySetLocation = hyperwalletKeySetLocation;
113✔
354
            return this;
113✔
355
        }
356

357
        public HyperwalletEncryptionBuilder jwsExpirationMinutes(Integer jwsExpirationMinutes) {
358
            this.jwsExpirationMinutes = jwsExpirationMinutes;
2✔
359
            return this;
2✔
360
        }
361

362
        public HyperwalletEncryptionBuilder proxy(Proxy proxy) {
363
            this.proxy = proxy;
2✔
364
            return this;
2✔
365
        }
366

367
        public HyperwalletEncryptionBuilder proxyUsername(String proxyUsername) {
368
            this.proxyUsername = proxyUsername;
2✔
369
            return this;
2✔
370
        }
371

372
        public HyperwalletEncryptionBuilder proxyPassword(String proxyPassword) {
373
            this.proxyPassword = proxyPassword;
2✔
374
            return this;
2✔
375
        }
376

377
        public HyperwalletEncryption build() {
378
            HyperwalletEncryption hyperwalletEncryption = new HyperwalletEncryption(encryptionAlgorithm, signAlgorithm, encryptionMethod,
129✔
379
                    clientPrivateKeySetLocation, hyperwalletKeySetLocation, jwsExpirationMinutes);
380
            if (proxy != null) {
125✔
381
                hyperwalletEncryption.setProxy(proxy);
1✔
382
            }
383
            if (proxyUsername != null) {
125✔
384
                hyperwalletEncryption.setProxyUsername(proxyUsername);
1✔
385
            }
386
            if (proxyPassword != null) {
125✔
387
                hyperwalletEncryption.setProxyPassword(proxyPassword);
1✔
388
            }
389
            return hyperwalletEncryption;
125✔
390
        }
391
    }
392
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc