-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathSealedBox.java
More file actions
231 lines (204 loc) · 8.26 KB
/
Copy pathSealedBox.java
File metadata and controls
231 lines (204 loc) · 8.26 KB
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/*
* Copyright 2016-2022 chronicle.software
*
* https://chronicle.software
*
* 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
*
* 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 net.openhft.chronicle.salt;
import net.openhft.chronicle.bytes.Bytes;
import net.openhft.chronicle.bytes.BytesStore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static net.openhft.chronicle.salt.Sodium.*;
public enum SealedBox {
; // none
/**
* Anonymously encrypt a message given a receivers public key
*
* @param message
* - the cleartext message
* @param publicKey
* - the recipients public key
* @return - the ciphertext BytesStore corresponding to the clearText message
*/
@NotNull
public static BytesStore encrypt(@NotNull BytesStore message, @NotNull PublicKey publicKey) {
return encrypt(null, message, publicKey);
}
/**
* As above, but result BytesStore is passed in first arg
*
* @param result
* - the ByteStore for the ciphertext result
* @param message
* - the cleartext message
* @param publicKey
* - the recipients public key
* @return - the ciphertext BytesStore (echoes arg1)
*/
@NotNull
public static BytesStore encrypt(@Nullable BytesStore result, @NotNull BytesStore message, @NotNull PublicKey publicKey) {
return encrypt(result, message, publicKey.store);
}
/**
* Underlying encrypt call taking explicit BytesStores Where possible the strongly-typed versions above should be preferred
*
* @param result
* - the ByteStore for the ciphertext result
* @param message
* - the cleartext message
* @param publicKey
* - the recipients public key
* @return - the ciphertext BytesStore (echoes arg1)
*/
@NotNull
public static BytesStore encrypt(@Nullable BytesStore result, @NotNull BytesStore message, @NotNull BytesStore publicKey) {
if (publicKey == null)
throw new RuntimeException("Encryption failed. Public key not available.");
long length = message.readRemaining();
long resultLength = length + CRYPTO_BOX_SEALBYTES;
result = Sodium.Util.setSize(result, resultLength);
checkValid(SODIUM.crypto_box_seal(result.addressForWrite(0), message.addressForRead(message.readPosition()), (int) length,
publicKey.addressForRead(publicKey.readPosition())), "Encryption failed");
return result;
}
/**
* Decrypt a message given own (receiver's) public and secret keys
*
* @param ciphertext
* - the encrypted message
* @param publicKey
* - receiver's public key
* @param secretKey
* - receiver's private key
* @return - the cleartext BytesStore
*/
@NotNull
public static BytesStore decrypt(@NotNull BytesStore ciphertext, @NotNull PublicKey publicKey, @NotNull SecretKey secretKey) {
return decrypt(null, ciphertext, publicKey, secretKey);
}
/**
* As above, but result BytesStore is passed in first arg
*
* @param result
* - the BytesStore for the cleartext result
* @param ciphertext
* - the encrypted message
* @param publicKey
* - receiver's public key
* @param secretKey
* - receiver's private key
* @return - the cleartext BytesStore (echoes arg1)
*/
@NotNull
public static BytesStore decrypt(@Nullable BytesStore result, @NotNull BytesStore ciphertext, @NotNull PublicKey publicKey,
@NotNull SecretKey secretKey) {
return decrypt(result, ciphertext, publicKey.store, secretKey.store);
}
/**
* Underlying decrypt call taking explicit BytesStores Where possible the strongly-typed versions above should be preferred
*
* @param result
* - the BytesStore for the cleartext result
* @param ciphertext
* - the encrypted message
* @param publicKey
* - receiver's public key
* @param secretKey
* - receiver's private key
* @return - the cleartext BytesStore
*/
@NotNull
public static BytesStore decrypt(@Nullable BytesStore result, @NotNull BytesStore ciphertext, @NotNull BytesStore publicKey,
@NotNull BytesStore secretKey) {
if (publicKey == null)
throw new RuntimeException("Decryption failed. Public key not available.");
if (secretKey == null)
throw new RuntimeException("Decryption failed. Private key not available.");
long length = ciphertext.readRemaining();
long resultLength = length - CRYPTO_BOX_SEALBYTES;
result = Sodium.Util.setSize(result, resultLength);
checkValid(
SODIUM.crypto_box_seal_open(result.addressForWrite(0), ciphertext.addressForRead(ciphertext.readPosition()), (int) length,
publicKey.addressForRead(publicKey.readPosition()), secretKey.addressForRead(secretKey.readPosition())),
"Decryption failed. Ciphertext failed verification");
return result;
}
/**
* Helper class to manage the public part of a KeyPair A PublicKey is created internally as part of a KeyPair, and provides a
* strongly-typed wrapper over the underlying BytesStore
*/
public static class PublicKey {
public final BytesStore store;
private PublicKey() {
this.store = Bytes.allocateDirect(CRYPTO_BOX_PUBLICKEYBYTES);
((Bytes) store).readLimit(CRYPTO_BOX_PUBLICKEYBYTES);
}
public long address() {
return store.addressForRead(0);
}
}
/**
* Helper class to manage the secret part of a KeyPair A SecretKey is created internally as part of a KeyPair, and provides a
* strongly-typed wrapper over the underlying BytesStore
*/
public static class SecretKey {
public final BytesStore store;
private SecretKey() {
this.store = Bytes.allocateDirect(CRYPTO_BOX_SECRETKEYBYTES);
((Bytes) store).readLimit(CRYPTO_BOX_SECRETKEYBYTES);
}
public long address() {
return store.addressForRead(0);
}
/**
* safely wipe the memory backing this key when finished
*/
public void wipe() {
SODIUM.sodium_memzero(address(), CRYPTO_BOX_SECRETKEYBYTES);
}
}
/**
* Helper class to handle KeyPair creation Explicitly named static methods are provided for consistency with EasyBox where they
* differentiate normal vs deterministic calls (As noted below, deterministic calls are not meaningful for sealed boxes)
*/
public static class KeyPair {
public final PublicKey publicKey;
public final SecretKey secretKey;
private KeyPair() {
this.secretKey = new SecretKey();
this.publicKey = new PublicKey();
SODIUM.crypto_box_keypair(publicKey.address(), secretKey.address());
}
/**
* Generate random public/private key pair
*
* @return a random public/private key pair
*/
public static KeyPair generate() {
return new KeyPair();
}
/**
* NB: For SealedBox, deterministic keys are of no use as the ephemeral key pair which libsodium sealed boxes use under the hood is
* not exposed and cannot be controlled. As a result, even with a deterministic key pair for the receiver the ciphertext for a given
* cleartext will change from run to run
*/
/**
* safely wipe the memory backing this key when finished
*/
public void wipe() {
secretKey.wipe();
}
}
}