Skip to content

Commit b1ec722

Browse files
authored
Merge pull request #24 from OSGP/feature/FDP-2637-using-bytebuffer-instead-of-bytearray
FDP-2637: Using ByteBuffer instead of ByteArray for Wrapper class.
2 parents 5024032 + b5a2b6a commit b1ec722

File tree

3 files changed

+48
-45
lines changed

3 files changed

+48
-45
lines changed

kafka-message-signing/src/main/kotlin/com/gxf/utilities/kafka/message/signing/MessageSigner.kt

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.gxf.utilities.kafka.avro.AvroEncoder
77
import com.gxf.utilities.kafka.message.wrapper.SignableMessageWrapper
88
import java.io.IOException
99
import java.io.UncheckedIOException
10+
import java.nio.ByteBuffer
1011
import java.nio.charset.StandardCharsets
1112
import java.security.*
1213
import java.security.spec.X509EncodedKeySpec
@@ -83,7 +84,7 @@ class MessageSigner(properties: MessageSigningProperties) {
8384
): ProducerRecord<String, out SpecificRecordBase> {
8485
if (this.signingEnabled) {
8586
val signature = this.signature(producerRecord)
86-
producerRecord.headers().add(RECORD_HEADER_KEY_SIGNATURE, signature)
87+
producerRecord.headers().add(RECORD_HEADER_KEY_SIGNATURE, signature.array())
8788
}
8889
return producerRecord
8990
}
@@ -101,15 +102,15 @@ class MessageSigner(properties: MessageSigningProperties) {
101102
* @throws UncheckedIOException if determining the bytes for the message throws an IOException.
102103
* @throws UncheckedSecurityException if the signing process throws a SignatureException.
103104
*/
104-
private fun signature(message: SignableMessageWrapper<*>): ByteArray {
105+
private fun signature(message: SignableMessageWrapper<*>): ByteBuffer {
105106
check(this.canSignMessages()) {
106107
"This MessageSigner is not configured for signing, it can only be used for verification"
107108
}
108109
val oldSignature = message.getSignature()
109110
message.setSignature(null)
110-
val byteArray = this.toByteArray(message)
111+
val byteBuffer = this.toByteBuffer(message)
111112
try {
112-
return signature(byteArray)
113+
return signature(byteBuffer)
113114
} catch (e: SignatureException) {
114115
throw UncheckedSecurityException("Unable to sign message", e)
115116
} finally {
@@ -130,16 +131,16 @@ class MessageSigner(properties: MessageSigningProperties) {
130131
* @throws UncheckedIOException if determining the bytes throws an IOException.
131132
* @throws UncheckedSecurityException if the signing process throws a SignatureException.
132133
*/
133-
private fun signature(producerRecord: ProducerRecord<String, out SpecificRecordBase>): ByteArray {
134+
private fun signature(producerRecord: ProducerRecord<String, out SpecificRecordBase>): ByteBuffer {
134135
check(this.canSignMessages()) {
135136
"This MessageSigner is not configured for signing, it can only be used for verification"
136137
}
137138
val oldSignatureHeader = producerRecord.headers().lastHeader(RECORD_HEADER_KEY_SIGNATURE)
138139
producerRecord.headers().remove(RECORD_HEADER_KEY_SIGNATURE)
139140
val specificRecordBase = producerRecord.value()
140-
val byteArray = this.toByteArray(specificRecordBase)
141+
val byteBuffer = this.toByteBuffer(specificRecordBase)
141142
try {
142-
return signature(byteArray)
143+
return signature(byteBuffer)
143144
} catch (e: SignatureException) {
144145
throw UncheckedSecurityException("Unable to sign message", e)
145146
} finally {
@@ -149,16 +150,16 @@ class MessageSigner(properties: MessageSigningProperties) {
149150
}
150151
}
151152

152-
private fun signature(byteArray: ByteArray): ByteArray {
153-
val messageBytes: ByteArray =
153+
private fun signature(byteBuffer: ByteBuffer): ByteBuffer {
154+
val messageBytes: ByteBuffer =
154155
if (this.stripAvroHeader) {
155-
this.stripAvroHeader(byteArray)
156+
this.stripAvroHeader(byteBuffer)
156157
} else {
157-
byteArray
158+
byteBuffer
158159
}
159160
val signingSignature = signatureInstance(signatureAlgorithm, signatureProvider, signingKey!!)
160161
signingSignature.update(messageBytes)
161-
return signingSignature.sign()
162+
return ByteBuffer.wrap(signingSignature.sign())
162163
}
163164

164165
fun canVerifyMessageSignatures(): Boolean {
@@ -179,14 +180,14 @@ class MessageSigner(properties: MessageSigningProperties) {
179180

180181
val messageSignature = message.getSignature()
181182

182-
if (messageSignature == null || messageSignature.isEmpty()) {
183+
if (messageSignature == null) {
183184
logger.error("This message does not contain a signature")
184185
return false
185186
}
186187

187188
try {
188189
message.setSignature(null)
189-
return this.verifySignatureBytes(messageSignature, this.toByteArray(message))
190+
return this.verifySignatureBytes(messageSignature, this.toByteBuffer(message))
190191
} catch (e: Exception) {
191192
logger.error("Unable to verify message signature", e)
192193
return false
@@ -221,50 +222,50 @@ class MessageSigner(properties: MessageSigningProperties) {
221222

222223
try {
223224
val specificRecordBase: SpecificRecordBase = consumerRecord.value()
224-
return this.verifySignatureBytes(signatureBytes, this.toByteArray(specificRecordBase))
225+
return this.verifySignatureBytes(ByteBuffer.wrap(signatureBytes), this.toByteBuffer(specificRecordBase))
225226
} catch (e: Exception) {
226227
logger.error("Unable to verify message signature", e)
227228
return false
228229
}
229230
}
230231

231232
@Throws(SignatureException::class)
232-
private fun verifySignatureBytes(signatureBytes: ByteArray, messageByteArray: ByteArray): Boolean {
233-
val messageBytes: ByteArray =
233+
private fun verifySignatureBytes(signatureBytes: ByteBuffer, messageByteBuffer: ByteBuffer): Boolean {
234+
val messageBytes: ByteBuffer =
234235
if (this.stripAvroHeader) {
235-
this.stripAvroHeader(messageByteArray)
236+
this.stripAvroHeader(messageByteBuffer)
236237
} else {
237-
messageByteArray
238+
messageByteBuffer
238239
}
239240
val verificationSignature = signatureInstance(signatureAlgorithm, signatureProvider, verificationKey!!)
240241
verificationSignature.update(messageBytes)
241-
return verificationSignature.verify(signatureBytes)
242+
return verificationSignature.verify(signatureBytes.array())
242243
}
243244

244-
private fun hasAvroHeader(bytes: ByteArray): Boolean {
245-
return (bytes.size >= AVRO_HEADER_LENGTH) &&
245+
private fun hasAvroHeader(bytes: ByteBuffer): Boolean {
246+
return (bytes.array().size >= AVRO_HEADER_LENGTH) &&
246247
((bytes[0].toInt() and 0xFF) == 0xC3) &&
247248
((bytes[1].toInt() and 0xFF) == 0x01)
248249
}
249250

250-
private fun stripAvroHeader(bytes: ByteArray): ByteArray {
251+
private fun stripAvroHeader(bytes: ByteBuffer): ByteBuffer {
251252
if (this.hasAvroHeader(bytes)) {
252-
return Arrays.copyOfRange(bytes, AVRO_HEADER_LENGTH, bytes.size)
253+
return ByteBuffer.wrap(Arrays.copyOfRange(bytes.array(), AVRO_HEADER_LENGTH, bytes.array().size))
253254
}
254255
return bytes
255256
}
256257

257-
private fun toByteArray(message: SignableMessageWrapper<*>): ByteArray {
258+
private fun toByteBuffer(message: SignableMessageWrapper<*>): ByteBuffer {
258259
try {
259-
return message.toByteArray()
260+
return message.toByteBuffer()
260261
} catch (e: IOException) {
261262
throw UncheckedIOException("Unable to determine bytes for message", e)
262263
}
263264
}
264265

265-
private fun toByteArray(message: SpecificRecordBase): ByteArray {
266+
private fun toByteBuffer(message: SpecificRecordBase): ByteBuffer {
266267
try {
267-
return AvroEncoder.encode(message)
268+
return ByteBuffer.wrap(AvroEncoder.encode(message))
268269
} catch (e: IOException) {
269270
throw UncheckedIOException("Unable to determine bytes for message", e)
270271
}

kafka-message-signing/src/main/kotlin/com/gxf/utilities/kafka/message/wrapper/SignableMessageWrapper.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@
44
package com.gxf.utilities.kafka.message.wrapper
55

66
import java.io.IOException
7+
import java.nio.ByteBuffer
78

89
/**
910
* Wrapper for signable messages. Because these messages are generated from Avro schemas, they can't be changed. This
1011
* wrapper unifies them for the MessageSigner.
1112
*/
1213
abstract class SignableMessageWrapper<T>(val message: T) {
1314

14-
/** @return ByteArray of the whole message */
15-
@Throws(IOException::class) abstract fun toByteArray(): ByteArray
15+
/** @return ByteBuffer of the whole message */
16+
@Throws(IOException::class) abstract fun toByteBuffer(): ByteBuffer
1617

17-
/** @return ByteArray of the signature in the message */
18-
abstract fun getSignature(): ByteArray?
18+
/** @return ByteBuffer of the signature in the message */
19+
abstract fun getSignature(): ByteBuffer?
1920

20-
/** @param signature The signature in ByteArray form to be set on the message */
21-
abstract fun setSignature(signature: ByteArray?)
21+
/** @param signature The signature in ByteBuffer form to be set on the message */
22+
abstract fun setSignature(signature: ByteBuffer?)
2223
}

kafka-message-signing/src/test/kotlin/com/gxf/utilities/kafka/message/signing/MessageSignerTest.kt

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package com.gxf.utilities.kafka.message.signing
55

66
import com.gxf.utilities.kafka.message.wrapper.SignableMessageWrapper
7+
import java.nio.ByteBuffer
78
import java.nio.charset.StandardCharsets
89
import java.security.SecureRandom
910
import java.util.Random
@@ -68,10 +69,10 @@ class MessageSignerTest {
6869
fun signsRecordHeaderReplacingSignature() {
6970
val randomSignature = this.randomSignature()
7071
val record = this.producerRecord()
71-
record.headers().add(MessageSigner.RECORD_HEADER_KEY_SIGNATURE, randomSignature)
72+
record.headers().add(MessageSigner.RECORD_HEADER_KEY_SIGNATURE, randomSignature.array())
7273

7374
val actualSignatureBefore = record.headers().lastHeader(MessageSigner.RECORD_HEADER_KEY_SIGNATURE).value()
74-
assertThat(actualSignatureBefore).isNotNull().isEqualTo(randomSignature)
75+
assertThat(actualSignatureBefore).isNotNull().isEqualTo(randomSignature.array())
7576

7677
messageSigner.signUsingHeader(record)
7778

@@ -129,7 +130,7 @@ class MessageSignerTest {
129130
fun doesNotVerifyRecordsWithIncorrectSignature() {
130131
val consumerRecord = this.consumerRecord()
131132
val randomSignature = this.randomSignature()
132-
consumerRecord.headers().add(MessageSigner.RECORD_HEADER_KEY_SIGNATURE, randomSignature)
133+
consumerRecord.headers().add(MessageSigner.RECORD_HEADER_KEY_SIGNATURE, randomSignature.array())
133134

134135
val validSignature = messageSigner.verifyUsingHeader(consumerRecord)
135136

@@ -160,7 +161,7 @@ class MessageSignerTest {
160161
return TestableWrapper()
161162
}
162163

163-
private fun messageWrapper(signature: ByteArray): TestableWrapper {
164+
private fun messageWrapper(signature: ByteBuffer): TestableWrapper {
164165
val testableWrapper = TestableWrapper()
165166
testableWrapper.setSignature(signature)
166167
return testableWrapper
@@ -185,14 +186,14 @@ class MessageSignerTest {
185186
return consumerRecord
186187
}
187188

188-
private fun randomSignature(): ByteArray {
189+
private fun randomSignature(): ByteBuffer {
189190
val random: Random = SecureRandom()
190191
val keySize = 2048
191192

192193
val signature = ByteArray(keySize / 8)
193194
random.nextBytes(signature)
194195

195-
return signature
196+
return ByteBuffer.wrap(signature)
196197
}
197198

198199
private fun producerRecord(): ProducerRecord<String, Message> {
@@ -225,17 +226,17 @@ class MessageSignerTest {
225226
}
226227

227228
private class TestableWrapper : SignableMessageWrapper<String>("Some test message") {
228-
private var signature: ByteArray? = null
229+
private var signature: ByteBuffer? = null
229230

230-
override fun toByteArray(): ByteArray {
231-
return message.toByteArray(StandardCharsets.UTF_8)
231+
override fun toByteBuffer(): ByteBuffer {
232+
return ByteBuffer.wrap(message.toByteArray(StandardCharsets.UTF_8))
232233
}
233234

234-
override fun getSignature(): ByteArray? {
235+
override fun getSignature(): ByteBuffer? {
235236
return this.signature
236237
}
237238

238-
override fun setSignature(signature: ByteArray?) {
239+
override fun setSignature(signature: ByteBuffer?) {
239240
this.signature = signature
240241
}
241242
}

0 commit comments

Comments
 (0)