1 | // Copyright (c) 2018, Yubico AB | |
2 | // All rights reserved. | |
3 | // | |
4 | // Redistribution and use in source and binary forms, with or without | |
5 | // modification, are permitted provided that the following conditions are met: | |
6 | // | |
7 | // 1. Redistributions of source code must retain the above copyright notice, this | |
8 | // list of conditions and the following disclaimer. | |
9 | // | |
10 | // 2. Redistributions in binary form must reproduce the above copyright notice, | |
11 | // this list of conditions and the following disclaimer in the documentation | |
12 | // and/or other materials provided with the distribution. | |
13 | // | |
14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
18 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
19 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
20 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
21 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
22 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | ||
25 | package com.yubico.internal.util; | |
26 | ||
27 | import java.io.IOException; | |
28 | import java.io.InputStream; | |
29 | import java.nio.ByteBuffer; | |
30 | import java.nio.ByteOrder; | |
31 | import java.util.Arrays; | |
32 | ||
33 | public class BinaryUtil { | |
34 | ||
35 | public static byte[] copy(byte[] bytes) { | |
36 |
1
1. copy : replaced return value with null for com/yubico/internal/util/BinaryUtil::copy → NO_COVERAGE |
return Arrays.copyOf(bytes, bytes.length); |
37 | } | |
38 | ||
39 | /** | |
40 | * @param bytes Bytes to encode | |
41 | */ | |
42 | public static String toHex(final byte[] bytes) { | |
43 |
1
1. toHex : Replaced integer multiplication with division → KILLED |
final char[] digits = new char[bytes.length * 2]; |
44 |
2
1. toHex : negated conditional → KILLED 2. toHex : changed conditional boundary → KILLED |
for (int i = 0; i < bytes.length; ++i) { |
45 |
1
1. toHex : Replaced integer multiplication with division → KILLED |
final int i2 = i * 2; |
46 |
2
1. toHex : Replaced Shift Right with Shift Left → KILLED 2. toHex : Replaced bitwise AND with OR → KILLED |
digits[i2] = Character.forDigit((bytes[i] >> 4) & 0x0f, 16); |
47 |
2
1. toHex : Replaced bitwise AND with OR → KILLED 2. toHex : Replaced integer addition with subtraction → KILLED |
digits[i2 + 1] = Character.forDigit(bytes[i] & 0x0f, 16); |
48 | } | |
49 |
1
1. toHex : replaced return value with "" for com/yubico/internal/util/BinaryUtil::toHex → KILLED |
return new String(digits); |
50 | } | |
51 | ||
52 | /** | |
53 | * @param hex String of hexadecimal digits to decode as bytes. | |
54 | */ | |
55 | public static byte[] fromHex(final String hex) { | |
56 |
2
1. fromHex : negated conditional → KILLED 2. fromHex : Replaced integer modulus with multiplication → KILLED |
if (hex.length() % 2 != 0) { |
57 | throw new IllegalArgumentException("Length of hex string is not even: " + hex); | |
58 | } | |
59 | ||
60 |
1
1. fromHex : Replaced integer division with multiplication → KILLED |
final byte[] result = new byte[hex.length() / 2]; |
61 |
2
1. fromHex : changed conditional boundary → KILLED 2. fromHex : negated conditional → KILLED |
for (int i = 0; i < hex.length(); ++i) { |
62 | final int d = Character.digit(hex.charAt(i), 16); | |
63 |
2
1. fromHex : changed conditional boundary → KILLED 2. fromHex : negated conditional → KILLED |
if (d < 0) { |
64 | throw new IllegalArgumentException("Invalid hex digit at index " + i + " in: " + hex); | |
65 | } | |
66 |
6
1. fromHex : Replaced integer multiplication with division → KILLED 2. fromHex : Replaced integer addition with subtraction → KILLED 3. fromHex : Replaced Shift Left with Shift Right → KILLED 4. fromHex : Replaced bitwise OR with AND → KILLED 5. fromHex : Replaced integer modulus with multiplication → KILLED 6. fromHex : Replaced integer division with multiplication → KILLED |
result[i / 2] |= d << (((i + 1) % 2) * 4); |
67 | } | |
68 |
1
1. fromHex : replaced return value with null for com/yubico/internal/util/BinaryUtil::fromHex → KILLED |
return result; |
69 | } | |
70 | ||
71 | /** | |
72 | * Parse a single byte from two hexadecimal characters. | |
73 | * | |
74 | * @param hex String of hexadecimal digits to decode as bytes. | |
75 | */ | |
76 | public static byte singleFromHex(String hex) { | |
77 |
1
1. singleFromHex : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → NO_COVERAGE |
ExceptionUtil.assertTrue( |
78 |
1
1. singleFromHex : negated conditional → NO_COVERAGE |
hex.length() == 2, "Argument must be exactly 2 hexadecimal characters, was: %s", hex); |
79 |
1
1. singleFromHex : replaced byte return with 0 for com/yubico/internal/util/BinaryUtil::singleFromHex → NO_COVERAGE |
return fromHex(hex)[0]; |
80 | } | |
81 | ||
82 | /** | |
83 | * Read one byte as an unsigned 8-bit integer. | |
84 | * | |
85 | * <p>Result is of type <code>short</code> because Java doesn't have unsigned types. | |
86 | * | |
87 | * @return A value between 0 and 255, inclusive. | |
88 | */ | |
89 | public static short getUint8(byte b) { | |
90 | // Prepend a zero so we can parse it as a signed int16 instead of a signed int8 | |
91 |
1
1. getUint8 : replaced short return with 0 for com/yubico/internal/util/BinaryUtil::getUint8 → KILLED |
return ByteBuffer.wrap(new byte[] {0, b}).order(ByteOrder.BIG_ENDIAN).getShort(); |
92 | } | |
93 | ||
94 | /** | |
95 | * Read 2 bytes as a big endian unsigned 16-bit integer. | |
96 | * | |
97 | * <p>Result is of type <code>int</code> because Java doesn't have unsigned types. | |
98 | * | |
99 | * @return A value between 0 and 2^16- 1, inclusive. | |
100 | */ | |
101 | public static int getUint16(byte[] bytes) { | |
102 |
1
1. getUint16 : negated conditional → KILLED |
if (bytes.length == 2) { |
103 | // Prepend zeroes so we can parse it as a signed int32 instead of a signed int16 | |
104 |
1
1. getUint16 : replaced int return with 0 for com/yubico/internal/util/BinaryUtil::getUint16 → KILLED |
return ByteBuffer.wrap(new byte[] {0, 0, bytes[0], bytes[1]}) |
105 | .order(ByteOrder.BIG_ENDIAN) | |
106 | .getInt(); | |
107 | } else { | |
108 | throw new IllegalArgumentException("Argument must be 2 bytes, was: " + bytes.length); | |
109 | } | |
110 | } | |
111 | ||
112 | /** | |
113 | * Read 4 bytes as a big endian unsigned 32-bit integer. | |
114 | * | |
115 | * <p>Result is of type <code>long</code> because Java doesn't have unsigned types. | |
116 | * | |
117 | * @return A value between 0 and 2^32 - 1, inclusive. | |
118 | */ | |
119 | public static long getUint32(byte[] bytes) { | |
120 |
1
1. getUint32 : negated conditional → KILLED |
if (bytes.length == 4) { |
121 | // Prepend zeroes so we can parse it as a signed int32 instead of a signed int16 | |
122 |
1
1. getUint32 : replaced long return with 0 for com/yubico/internal/util/BinaryUtil::getUint32 → KILLED |
return ByteBuffer.wrap(new byte[] {0, 0, 0, 0, bytes[0], bytes[1], bytes[2], bytes[3]}) |
123 | .order(ByteOrder.BIG_ENDIAN) | |
124 | .getLong(); | |
125 | } else { | |
126 | throw new IllegalArgumentException("Argument must be 4 bytes, was: " + bytes.length); | |
127 | } | |
128 | } | |
129 | ||
130 | public static byte[] encodeUint16(int value) { | |
131 |
3
1. encodeUint16 : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED 2. encodeUint16 : changed conditional boundary → KILLED 3. encodeUint16 : negated conditional → KILLED |
ExceptionUtil.assertTrue(value >= 0, "Argument must be non-negative, was: %d", value); |
132 |
3
1. encodeUint16 : changed conditional boundary → SURVIVED 2. encodeUint16 : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → KILLED 3. encodeUint16 : negated conditional → KILLED |
ExceptionUtil.assertTrue( |
133 | value < 65536, "Argument must be smaller than 2^16=65536, was: %d", value); | |
134 | ||
135 | ByteBuffer b = ByteBuffer.allocate(4); | |
136 | b.order(ByteOrder.BIG_ENDIAN); | |
137 | b.putInt(value); | |
138 | b.rewind(); | |
139 |
1
1. encodeUint16 : replaced return value with null for com/yubico/internal/util/BinaryUtil::encodeUint16 → KILLED |
return Arrays.copyOfRange(b.array(), 2, 4); |
140 | } | |
141 | ||
142 | public static byte[] encodeUint32(long value) { | |
143 |
3
1. encodeUint32 : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → NO_COVERAGE 2. encodeUint32 : negated conditional → NO_COVERAGE 3. encodeUint32 : changed conditional boundary → NO_COVERAGE |
ExceptionUtil.assertTrue(value >= 0, "Argument must be non-negative, was: %d", value); |
144 |
3
1. encodeUint32 : removed call to com/yubico/internal/util/ExceptionUtil::assertTrue → NO_COVERAGE 2. encodeUint32 : negated conditional → NO_COVERAGE 3. encodeUint32 : changed conditional boundary → NO_COVERAGE |
ExceptionUtil.assertTrue( |
145 | value < 4294967296L, "Argument must be smaller than 2^32=4294967296, was: %d", value); | |
146 | ||
147 | ByteBuffer b = ByteBuffer.allocate(8); | |
148 | b.order(ByteOrder.BIG_ENDIAN); | |
149 | b.putLong(value); | |
150 | b.rewind(); | |
151 |
1
1. encodeUint32 : replaced return value with null for com/yubico/internal/util/BinaryUtil::encodeUint32 → NO_COVERAGE |
return Arrays.copyOfRange(b.array(), 4, 8); |
152 | } | |
153 | ||
154 | public static byte[] readAll(InputStream is) throws IOException { | |
155 | byte[] buffer = new byte[1024]; | |
156 | int bufferLen = 0; | |
157 | while (true) { | |
158 |
1
1. readAll : Replaced integer subtraction with addition → NO_COVERAGE |
final int moreLen = is.read(buffer, bufferLen, buffer.length - bufferLen); |
159 |
2
1. readAll : changed conditional boundary → NO_COVERAGE 2. readAll : negated conditional → NO_COVERAGE |
if (moreLen <= 0) { |
160 |
1
1. readAll : replaced return value with null for com/yubico/internal/util/BinaryUtil::readAll → NO_COVERAGE |
return Arrays.copyOf(buffer, bufferLen); |
161 | } else { | |
162 |
1
1. readAll : Replaced integer addition with subtraction → NO_COVERAGE |
bufferLen += moreLen; |
163 |
1
1. readAll : negated conditional → NO_COVERAGE |
if (bufferLen == buffer.length) { |
164 |
1
1. readAll : Replaced integer multiplication with division → NO_COVERAGE |
buffer = Arrays.copyOf(buffer, buffer.length * 2); |
165 | } | |
166 | } | |
167 | } | |
168 | } | |
169 | } | |
Mutations | ||
36 |
1.1 |
|
43 |
1.1 |
|
44 |
1.1 2.2 |
|
45 |
1.1 |
|
46 |
1.1 2.2 |
|
47 |
1.1 2.2 |
|
49 |
1.1 |
|
56 |
1.1 2.2 |
|
60 |
1.1 |
|
61 |
1.1 2.2 |
|
63 |
1.1 2.2 |
|
66 |
1.1 2.2 3.3 4.4 5.5 6.6 |
|
68 |
1.1 |
|
77 |
1.1 |
|
78 |
1.1 |
|
79 |
1.1 |
|
91 |
1.1 |
|
102 |
1.1 |
|
104 |
1.1 |
|
120 |
1.1 |
|
122 |
1.1 |
|
131 |
1.1 2.2 3.3 |
|
132 |
1.1 2.2 3.3 |
|
139 |
1.1 |
|
143 |
1.1 2.2 3.3 |
|
144 |
1.1 2.2 3.3 |
|
151 |
1.1 |
|
158 |
1.1 |
|
159 |
1.1 2.2 |
|
160 |
1.1 |
|
162 |
1.1 |
|
163 |
1.1 |
|
164 |
1.1 |