Token.java

1
/**
2
   Copyright 2017 Carlos Macasaet
3
4
   Licensed under the Apache License, Version 2.0 (the "License");
5
   you may not use this file except in compliance with the License.
6
   You may obtain a copy of the License at
7
8
       http://www.apache.org/licenses/LICENSE-2.0
9
10
   Unless required by applicable law or agreed to in writing, software
11
   distributed under the License is distributed on an "AS IS" BASIS,
12
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
   See the License for the specific language governing permissions and
14
   limitations under the License.
15
 */
16
package com.macasaet.fernet;
17
18
import static com.macasaet.fernet.Constants.charset;
19
import static com.macasaet.fernet.Constants.cipherTextBlockSize;
20
import static com.macasaet.fernet.Constants.decoder;
21
import static com.macasaet.fernet.Constants.encoder;
22
import static com.macasaet.fernet.Constants.initializationVectorBytes;
23
import static com.macasaet.fernet.Constants.minimumTokenBytes;
24
import static com.macasaet.fernet.Constants.signatureBytes;
25
import static com.macasaet.fernet.Constants.supportedVersion;
26
import static com.macasaet.fernet.Constants.tokenStaticBytes;
27
28
import java.io.ByteArrayInputStream;
29
import java.io.ByteArrayOutputStream;
30
import java.io.DataInputStream;
31
import java.io.DataOutputStream;
32
import java.io.IOException;
33
import java.io.OutputStream;
34
import java.math.BigInteger;
35
import java.security.MessageDigest;
36
import java.security.SecureRandom;
37
import java.time.Instant;
38
import java.util.Base64.Encoder;
39
import java.util.Collection;
40
41
import javax.crypto.spec.IvParameterSpec;
42
43
/**
44
 * A Fernet token.
45
 *
46
 * <p>Copyright &copy; 2017 Carlos Macasaet.</p>
47
 *
48
 * @author Carlos Macasaet
49
 */
50
@SuppressWarnings({"PMD.TooManyMethods", "PMD.AvoidDuplicateLiterals"})
51
/*
52
 * TooManyMethods can be avoided by making the following API-breaking changes:
53
 * * remove the static `generate` methods and introduce a `TokenFactory` or `TokenBuilder`
54
 * * remove the public `validateAndDecrypt` methods since they are already available in the `Validator` interface
55
 * 
56
 * AvoidDuplicateLiterals is from the method-level @SuppressWarnings annotations
57
 */
58
public class Token {
59
60
    private final byte version;
61
    private final Instant timestamp;
62
    private final IvParameterSpec initializationVector;
63
    private final byte[] cipherText;
64
    private final byte[] hmac;
65
66
    /**
67
     * <p>Initialise a new Token from raw components. No validation of the signature is performed. However, the other
68
     * fields are validated to ensure they conform to the Fernet specification.</p>
69
     *
70
     * <p>Warning: Subsequent modifications to the input arrays will write through to this object.</p>
71
     *
72
     * @param version
73
     *            The version of the Fernet token specification. Currently, only 0x80 is supported.
74
     * @param timestamp
75
     *            the time the token was generated
76
     * @param initializationVector
77
     *            the randomly-generated bytes used to initialise the encryption cipher
78
     * @param cipherText
79
     *            the encrypted the encrypted payload
80
     * @param hmac
81
     *            the signature of the token
82
     */
83
    @SuppressWarnings({"PMD.ArrayIsStoredDirectly", "PMD.CyclomaticComplexity"})
84
    protected Token(final byte version, final Instant timestamp, final IvParameterSpec initializationVector,
85
            final byte[] cipherText, final byte[] hmac) {
86 1 1. <init> : negated conditional → KILLED
        if (version != supportedVersion) {
87
            throw new IllegalTokenException("Unsupported version: " + version);
88
        }
89 1 1. <init> : negated conditional → KILLED
        if (timestamp == null) {
90
            throw new IllegalTokenException("timestamp cannot be null");
91
        }
92 2 1. <init> : negated conditional → KILLED
2. <init> : negated conditional → KILLED
        if (initializationVector == null || initializationVector.getIV().length != initializationVectorBytes) {
93
            throw new IllegalTokenException("Initialization Vector must be 128 bits");
94
        }
95 3 1. <init> : Replaced integer modulus with multiplication → KILLED
2. <init> : negated conditional → KILLED
3. <init> : negated conditional → KILLED
        if (cipherText == null || cipherText.length % cipherTextBlockSize != 0) {
96
            throw new IllegalTokenException("Ciphertext must be a multiple of 128 bits");
97
        }
98 2 1. <init> : negated conditional → KILLED
2. <init> : negated conditional → KILLED
        if (hmac == null || hmac.length != signatureBytes) {
99
            throw new IllegalTokenException("hmac must be 256 bits");
100
        }
101
        this.version = version;
102
        this.timestamp = timestamp;
103
        this.initializationVector = initializationVector;
104
        this.cipherText = cipherText;
105
        this.hmac = hmac;
106
    }
107
108
    /**
109
     * Read a Token from bytes. This does NOT validate that the token was
110
     * generated using a valid {@link Key}.
111
     *
112
     * @param bytes a Fernet token in the form Version | Timestamp | IV |
113
     *              Ciphertext | HMAC
114
     * @return a new Token
115
     * @throws IllegalTokenException if the input string cannot be a valid
116
     *                               token irrespective of key or timestamp.
117
     */
118
    @SuppressWarnings({"PMD.PrematureDeclaration", "PMD.DataflowAnomalyAnalysis"})
119
    public static Token fromBytes(final byte[] bytes) {
120 2 1. fromBytes : changed conditional boundary → KILLED
2. fromBytes : negated conditional → KILLED
        if (bytes.length < minimumTokenBytes) {
121
            throw new IllegalTokenException("Not enough bits to generate a Token");
122
        }
123 2 1. fromBytes : removed call to java/io/ByteArrayInputStream::close → NO_COVERAGE
2. fromBytes : removed call to java/lang/Throwable::addSuppressed → NO_COVERAGE
        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {
124 2 1. fromBytes : removed call to java/io/DataInputStream::close → NO_COVERAGE
2. fromBytes : removed call to java/lang/Throwable::addSuppressed → NO_COVERAGE
            try (DataInputStream dataStream = new DataInputStream(inputStream)) {
125
                final byte version = dataStream.readByte();
126
                final long timestampSeconds = dataStream.readLong();
127
128
                final byte[] initializationVector = read(dataStream, initializationVectorBytes);
129 1 1. fromBytes : Replaced integer subtraction with addition → KILLED
                final byte[] cipherText = read(dataStream, bytes.length - tokenStaticBytes);
130
                final byte[] hmac = read(dataStream, signatureBytes);
131
132 1 1. fromBytes : negated conditional → KILLED
                if (dataStream.read() != -1) {
133
                    throw new IllegalTokenException("more bits found");
134
                }
135
136 1 1. fromBytes : mutated return of Object value for com/macasaet/fernet/Token::fromBytes to ( if (x != null) null else throw new RuntimeException ) → KILLED
                return new Token(version, Instant.ofEpochSecond(timestampSeconds),
137
                        new IvParameterSpec(initializationVector), cipherText, hmac);
138 1 1. fromBytes : removed call to java/io/DataInputStream::close → SURVIVED
            }
139 1 1. fromBytes : removed call to java/io/ByteArrayInputStream::close → SURVIVED
        } catch (final IOException ioe) {
140
            // this should not happen as I/O is from memory and stream
141
            // length is verified ahead of time
142
            throw new IllegalStateException(ioe.getMessage(), ioe);
143
        }
144
    }
145
146
    protected static byte[] read(final DataInputStream stream, final int numBytes) throws IOException {
147
        final byte[] retval = new byte[numBytes];
148
        final int bytesRead = stream.read(retval);
149 2 1. read : changed conditional boundary → KILLED
2. read : negated conditional → KILLED
        if (bytesRead < numBytes) {
150
            throw new IllegalTokenException("Not enough bits to generate a Token");
151
        }
152 1 1. read : mutated return of Object value for com/macasaet/fernet/Token::read to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return retval;
153
    }
154
155
    /**
156
     * Deserialise a Base64 URL Fernet token string. This does NOT validate that the token was generated using a valid {@link Key}.
157
     *
158
     * @param string
159
     *            the Base 64 URL encoding of a token in the form Version | Timestamp | IV | Ciphertext | HMAC
160
     * @return a new Token
161
     * @throws IllegalTokenException
162
     *             if the input string cannot be a valid token irrespective of key or timestamp
163
     */
164
    public static Token fromString(final String string) {
165 1 1. fromString : mutated return of Object value for com/macasaet/fernet/Token::fromString to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return fromBytes(decoder.decode(string));
166
    }
167
168
    /**
169
     * Convenience method to generate a new Fernet token with a string payload.
170
     *
171
     * @param key the secret key for encrypting <em>plainText</em> and signing the token
172
     * @param plainText the payload to embed in the token
173
     * @return a unique Fernet token
174
     */
175
    public static Token generate(final Key key, final String plainText) {
176
        return generate(new SecureRandom(), key, plainText);
177
    }
178
179
    /**
180
     * Convenience method to generate a new Fernet token with a string payload.
181
     *
182
     * @param random a source of entropy for your application
183
     * @param key the secret key for encrypting <em>plainText</em> and signing the token
184
     * @param plainText the payload to embed in the token
185
     * @return a unique Fernet token
186
     */
187
    public static Token generate(final SecureRandom random, final Key key, final String plainText) {
188 1 1. generate : mutated return of Object value for com/macasaet/fernet/Token::generate to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return generate(random, key, plainText.getBytes(charset));
189
    }
190
191
    /**
192
     * Convenience method to generate a new Fernet token.
193
     *
194
     * @param key the secret key for encrypting <em>payload</em> and signing the token
195
     * @param payload the unencrypted data to embed in the token
196
     * @return a unique Fernet token
197
     */
198
    public static Token generate(final Key key, final byte[] payload) {
199
        return generate(new SecureRandom(), key, payload);
200
    }
201
202
    /**
203
     * Generate a new Fernet token.
204
     *
205
     * @param random a source of entropy for your application
206
     * @param key the secret key for encrypting <em>payload</em> and signing the token
207
     * @param payload the unencrypted data to embed in the token
208
     * @return a unique Fernet token
209
     */
210
    public static Token generate(final SecureRandom random, final Key key, final byte[] payload) {
211
        final IvParameterSpec initializationVector = generateInitializationVector(random);
212
        final byte[] cipherText = key.encrypt(payload, initializationVector);
213
        final Instant timestamp = Instant.now();
214
        final byte[] hmac = key.sign(supportedVersion, timestamp, initializationVector, cipherText);
215 1 1. generate : mutated return of Object value for com/macasaet/fernet/Token::generate to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return new Token(supportedVersion, timestamp, initializationVector, cipherText, hmac);
216
    }
217
218
    /**
219
     * Check the validity of this token. 
220
     *
221
     * @param key the secret key against which to validate the token
222
     * @param validator an object that encapsulates the validation parameters (e.g. TTL)
223
     * @return the decrypted, deserialised payload of this token
224
     * @throws TokenValidationException if <em>key</em> was NOT used to generate this token
225
     */
226
    @SuppressWarnings("PMD.LawOfDemeter")
227
    public <T> T validateAndDecrypt(final Key key, final Validator<T> validator) {
228 1 1. validateAndDecrypt : mutated return of Object value for com/macasaet/fernet/Token::validateAndDecrypt to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return validator.validateAndDecrypt(key, this);
229
    }
230
231
    /**
232
     * Check the validity of this token against a collection of keys. Use this if you have implemented key rotation.
233
     *
234
     * @param keys the active keys which may have been used to generate token
235
     * @param validator an object that encapsulates the validation parameters (e.g. TTL)
236
     * @return the decrypted, deserialised payload of this token
237
     * @throws TokenValidationException if none of the keys were used to generate this token
238
     */
239
    @SuppressWarnings("PMD.LawOfDemeter")
240
    public <T> T validateAndDecrypt(final Collection<? extends Key> keys, final Validator<T> validator) {
241 1 1. validateAndDecrypt : mutated return of Object value for com/macasaet/fernet/Token::validateAndDecrypt to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return validator.validateAndDecrypt(keys, this);
242
    }
243
244
    @SuppressWarnings({"PMD.ConfusingTernary", "PMD.LawOfDemeter"})
245
    protected byte[] validateAndDecrypt(final Key key, final Instant earliestValidInstant,
246
            final Instant latestValidInstant) {
247 1 1. validateAndDecrypt : negated conditional → KILLED
        if (getVersion() != (byte) 0x80) {
248
            throw new TokenValidationException("Invalid version");
249 1 1. validateAndDecrypt : negated conditional → KILLED
        } else if (!getTimestamp().isAfter(earliestValidInstant)) {
250
            throw new TokenExpiredException("Token is expired");
251 1 1. validateAndDecrypt : negated conditional → KILLED
        } else if (!getTimestamp().isBefore(latestValidInstant)) {
252
            throw new TokenValidationException("Token timestamp is in the future (clock skew).");
253 1 1. validateAndDecrypt : negated conditional → KILLED
        } else if (!isValidSignature(key)) {
254
            throw new TokenValidationException("Signature does not match.");
255
        }
256 1 1. validateAndDecrypt : mutated return of Object value for com/macasaet/fernet/Token::validateAndDecrypt to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return key.decrypt(getCipherText(), getInitializationVector());
257
    }
258
259
    /**
260
     * @return the Base 64 URL encoding of this token in the form Version | Timestamp | IV | Ciphertext | HMAC
261
     */
262
    @SuppressWarnings("PMD.LawOfDemeter")
263
    public String serialise() {
264 2 1. serialise : removed call to java/io/ByteArrayOutputStream::close → NO_COVERAGE
2. serialise : removed call to java/lang/Throwable::addSuppressed → NO_COVERAGE
        try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream(
265 1 1. serialise : Replaced integer addition with subtraction → KILLED
                tokenStaticBytes + getCipherText().length)) {
266 1 1. serialise : removed call to com/macasaet/fernet/Token::writeTo → KILLED
            writeTo(byteStream);
267 1 1. serialise : mutated return of Object value for com/macasaet/fernet/Token::serialise to ( if (x != null) null else throw new RuntimeException ) → KILLED
            return getEncoder().encodeToString(byteStream.toByteArray());
268 1 1. serialise : removed call to java/io/ByteArrayOutputStream::close → SURVIVED
        } catch (final IOException e) {
269
            // this should not happen as IO is to memory only
270
            throw new IllegalStateException(e.getMessage(), e);
271
        }
272
    }
273
274
    /**
275
     * Write the raw bytes of this token to the specified output stream.
276
     *
277
     * @param outputStream
278
     *            the target
279
     * @throws IOException
280
     *             if data cannot be written to the underlying stream
281
     */
282
    @SuppressWarnings("PMD.LawOfDemeter")
283
    public void writeTo(final OutputStream outputStream) throws IOException {
284 2 1. writeTo : removed call to java/io/DataOutputStream::close → NO_COVERAGE
2. writeTo : removed call to java/lang/Throwable::addSuppressed → NO_COVERAGE
        try (DataOutputStream dataStream = new DataOutputStream(outputStream)) {
285 1 1. writeTo : removed call to java/io/DataOutputStream::writeByte → KILLED
            dataStream.writeByte(getVersion());
286 1 1. writeTo : removed call to java/io/DataOutputStream::writeLong → KILLED
            dataStream.writeLong(getTimestamp().getEpochSecond());
287 1 1. writeTo : removed call to java/io/DataOutputStream::write → KILLED
            dataStream.write(getInitializationVector().getIV());
288 1 1. writeTo : removed call to java/io/DataOutputStream::write → KILLED
            dataStream.write(getCipherText());
289 1 1. writeTo : removed call to java/io/DataOutputStream::write → KILLED
            dataStream.write(getHmac());
290 1 1. writeTo : removed call to java/io/DataOutputStream::close → SURVIVED
        }
291
    }
292
293
    /**
294
     * @return the Fernet specification version of this token
295
     */
296
    public byte getVersion() {
297 1 1. getVersion : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return version;
298
    }
299
300
    /**
301
     * @return the time that this token was generated
302
     */
303
    public Instant getTimestamp() {
304 1 1. getTimestamp : mutated return of Object value for com/macasaet/fernet/Token::getTimestamp to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return timestamp;
305
    }
306
307
    /**
308
     * @return the initialisation vector used to encrypt the token contents
309
     */
310
    public IvParameterSpec getInitializationVector() {
311 1 1. getInitializationVector : mutated return of Object value for com/macasaet/fernet/Token::getInitializationVector to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return initializationVector;
312
    }
313
314
    public String toString() {
315
        final StringBuilder builder = new StringBuilder(107);
316
        builder.append("Token [version=").append(String.format("0x%x", new BigInteger(1, new byte[] {getVersion()})))
317
                .append(", timestamp=").append(getTimestamp())
318
                .append(", hmac=").append(encoder.encodeToString(getHmac())).append(']');
319 1 1. toString : mutated return of Object value for com/macasaet/fernet/Token::toString to ( if (x != null) null else throw new RuntimeException ) → SURVIVED
        return builder.toString();
320
    }
321
322
    protected static IvParameterSpec generateInitializationVector(final SecureRandom random) {
323 1 1. generateInitializationVector : mutated return of Object value for com/macasaet/fernet/Token::generateInitializationVector to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return new IvParameterSpec(generateInitializationVectorBytes(random));
324
    }
325
326
    protected static byte[] generateInitializationVectorBytes(final SecureRandom random) {
327
        final byte[] retval = new byte[initializationVectorBytes];
328
        random.nextBytes(retval);
329 1 1. generateInitializationVectorBytes : mutated return of Object value for com/macasaet/fernet/Token::generateInitializationVectorBytes to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return retval;
330
    }
331
332
    /**
333
     * Recompute the HMAC signature of the token with the stored shared secret key.
334
     *
335
     * @param key
336
     *            the shared secret key against which to validate the token
337
     * @return true if and only if the signature on the token was generated using the supplied key
338
     */
339
    public boolean isValidSignature(final Key key) {
340
        final byte[] computedHmac = key.sign(getVersion(), getTimestamp(), getInitializationVector(),
341
                getCipherText());
342 1 1. isValidSignature : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return MessageDigest.isEqual(getHmac(), computedHmac);
343
    }
344
345
    protected Encoder getEncoder() {
346 1 1. getEncoder : mutated return of Object value for com/macasaet/fernet/Token::getEncoder to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return encoder;
347
    }
348
349
    /**
350
     * Warning: modifications to the returned array will write through to this object.
351
     *
352
     * @return the raw encrypted payload bytes
353
     */
354
    @SuppressWarnings("PMD.MethodReturnsInternalArray")
355
    protected byte[] getCipherText() {
356 1 1. getCipherText : mutated return of Object value for com/macasaet/fernet/Token::getCipherText to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return cipherText;
357
    }
358
359
    /**
360
     * Warning: modifications to the returned array will write through to this object.
361
     *
362
     * @return the HMAC 256 signature of this token
363
     */
364
    @SuppressWarnings("PMD.MethodReturnsInternalArray")
365
    protected byte[] getHmac() {
366 1 1. getHmac : mutated return of Object value for com/macasaet/fernet/Token::getHmac to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return hmac;
367
    }
368
369
}

Mutations

86

1.1
Location : <init>
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

89

1.1
Location : <init>
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

92

1.1
Location : <init>
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

2.2
Location : <init>
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

95

1.1
Location : <init>
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
Replaced integer modulus with multiplication → KILLED

2.2
Location : <init>
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

3.3
Location : <init>
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

98

1.1
Location : <init>
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

2.2
Location : <init>
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

120

1.1
Location : fromBytes
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
changed conditional boundary → KILLED

2.2
Location : fromBytes
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

123

1.1
Location : fromBytes
Killed by : none
removed call to java/io/ByteArrayInputStream::close → NO_COVERAGE

2.2
Location : fromBytes
Killed by : none
removed call to java/lang/Throwable::addSuppressed → NO_COVERAGE

124

1.1
Location : fromBytes
Killed by : none
removed call to java/io/DataInputStream::close → NO_COVERAGE

2.2
Location : fromBytes
Killed by : none
removed call to java/lang/Throwable::addSuppressed → NO_COVERAGE

129

1.1
Location : fromBytes
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
Replaced integer subtraction with addition → KILLED

132

1.1
Location : fromBytes
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

136

1.1
Location : fromBytes
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::fromBytes to ( if (x != null) null else throw new RuntimeException ) → KILLED

138

1.1
Location : fromBytes
Killed by : none
removed call to java/io/DataInputStream::close → SURVIVED

139

1.1
Location : fromBytes
Killed by : none
removed call to java/io/ByteArrayInputStream::close → SURVIVED

149

1.1
Location : read
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
changed conditional boundary → KILLED

2.2
Location : read
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

152

1.1
Location : read
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::read to ( if (x != null) null else throw new RuntimeException ) → KILLED

165

1.1
Location : fromString
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::fromString to ( if (x != null) null else throw new RuntimeException ) → KILLED

188

1.1
Location : generate
Killed by : com.macasaet.fernet.TokenTest.testGenerate(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::generate to ( if (x != null) null else throw new RuntimeException ) → KILLED

215

1.1
Location : generate
Killed by : com.macasaet.fernet.TokenTest.verifyTokenGenerationWithDefaultEntropySource(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::generate to ( if (x != null) null else throw new RuntimeException ) → KILLED

228

1.1
Location : validateAndDecrypt
Killed by : com.macasaet.fernet.TokenTest.testGenerate(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::validateAndDecrypt to ( if (x != null) null else throw new RuntimeException ) → KILLED

241

1.1
Location : validateAndDecrypt
Killed by : com.macasaet.fernet.TokenTest.verifyKeyInRotationCanDecryptToken(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::validateAndDecrypt to ( if (x != null) null else throw new RuntimeException ) → KILLED

247

1.1
Location : validateAndDecrypt
Killed by : com.macasaet.fernet.TokenTest.testGenerate(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

249

1.1
Location : validateAndDecrypt
Killed by : com.macasaet.fernet.TokenTest.testGenerate(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

251

1.1
Location : validateAndDecrypt
Killed by : com.macasaet.fernet.TokenTest.testGenerate(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

253

1.1
Location : validateAndDecrypt
Killed by : com.macasaet.fernet.TokenTest.testGenerate(com.macasaet.fernet.TokenTest)
negated conditional → KILLED

256

1.1
Location : validateAndDecrypt
Killed by : com.macasaet.fernet.TokenTest.testGenerate(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::validateAndDecrypt to ( if (x != null) null else throw new RuntimeException ) → KILLED

264

1.1
Location : serialise
Killed by : none
removed call to java/io/ByteArrayOutputStream::close → NO_COVERAGE

2.2
Location : serialise
Killed by : none
removed call to java/lang/Throwable::addSuppressed → NO_COVERAGE

265

1.1
Location : serialise
Killed by : com.macasaet.fernet.example.pb.ProtocolBuffersExampleIT.testRenewal(com.macasaet.fernet.example.pb.ProtocolBuffersExampleIT)
Replaced integer addition with subtraction → KILLED

266

1.1
Location : serialise
Killed by : com.macasaet.fernet.TokenTest.testSerialise(com.macasaet.fernet.TokenTest)
removed call to com/macasaet/fernet/Token::writeTo → KILLED

267

1.1
Location : serialise
Killed by : com.macasaet.fernet.TokenTest.testSerialise(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::serialise to ( if (x != null) null else throw new RuntimeException ) → KILLED

268

1.1
Location : serialise
Killed by : none
removed call to java/io/ByteArrayOutputStream::close → SURVIVED

284

1.1
Location : writeTo
Killed by : none
removed call to java/io/DataOutputStream::close → NO_COVERAGE

2.2
Location : writeTo
Killed by : none
removed call to java/lang/Throwable::addSuppressed → NO_COVERAGE

285

1.1
Location : writeTo
Killed by : com.macasaet.fernet.TokenTest.testSerialise(com.macasaet.fernet.TokenTest)
removed call to java/io/DataOutputStream::writeByte → KILLED

286

1.1
Location : writeTo
Killed by : com.macasaet.fernet.TokenTest.testSerialise(com.macasaet.fernet.TokenTest)
removed call to java/io/DataOutputStream::writeLong → KILLED

287

1.1
Location : writeTo
Killed by : com.macasaet.fernet.TokenTest.testSerialise(com.macasaet.fernet.TokenTest)
removed call to java/io/DataOutputStream::write → KILLED

288

1.1
Location : writeTo
Killed by : com.macasaet.fernet.TokenTest.testSerialise(com.macasaet.fernet.TokenTest)
removed call to java/io/DataOutputStream::write → KILLED

289

1.1
Location : writeTo
Killed by : com.macasaet.fernet.TokenTest.testSerialise(com.macasaet.fernet.TokenTest)
removed call to java/io/DataOutputStream::write → KILLED

290

1.1
Location : writeTo
Killed by : none
removed call to java/io/DataOutputStream::close → SURVIVED

297

1.1
Location : getVersion
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

304

1.1
Location : getTimestamp
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::getTimestamp to ( if (x != null) null else throw new RuntimeException ) → KILLED

311

1.1
Location : getInitializationVector
Killed by : com.macasaet.fernet.TokenTest.testFromString(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::getInitializationVector to ( if (x != null) null else throw new RuntimeException ) → KILLED

319

1.1
Location : toString
Killed by : none
mutated return of Object value for com/macasaet/fernet/Token::toString to ( if (x != null) null else throw new RuntimeException ) → SURVIVED

323

1.1
Location : generateInitializationVector
Killed by : com.macasaet.fernet.TokenTest.verifyTokenGenerationWithDefaultEntropySource(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::generateInitializationVector to ( if (x != null) null else throw new RuntimeException ) → KILLED

329

1.1
Location : generateInitializationVectorBytes
Killed by : com.macasaet.fernet.TokenTest.verifyTokenGenerationWithDefaultEntropySource(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::generateInitializationVectorBytes to ( if (x != null) null else throw new RuntimeException ) → KILLED

342

1.1
Location : isValidSignature
Killed by : com.macasaet.fernet.TokenTest.verifyTokenGenerationWithDefaultEntropySource(com.macasaet.fernet.TokenTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

346

1.1
Location : getEncoder
Killed by : com.macasaet.fernet.TokenTest.testSerialise(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::getEncoder to ( if (x != null) null else throw new RuntimeException ) → KILLED

356

1.1
Location : getCipherText
Killed by : com.macasaet.fernet.TokenTest.verifyTokenGenerationWithDefaultEntropySource(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::getCipherText to ( if (x != null) null else throw new RuntimeException ) → KILLED

366

1.1
Location : getHmac
Killed by : com.macasaet.fernet.TokenTest.verifyTokenGenerationWithDefaultEntropySource(com.macasaet.fernet.TokenTest)
mutated return of Object value for com/macasaet/fernet/Token::getHmac to ( if (x != null) null else throw new RuntimeException ) → KILLED

Active mutators

Tests examined


Report generated by PIT 1.4.10