Skip to content

Commit f9f0b1a

Browse files
committed
[KYUUBI #7374] Fix static zero IV in InternalSecurityAccessor
### Why are the changes needed? Replace the hardcoded IV with a per-encryption random IV. ### How was this patch tested? Covered by existing unit test `InternalSecurityAccessorSuite` ### Was this patch authored or co-authored using generative AI tooling? Generated-by: Claude Code (Claude Opus 4.6) Closes #7374 from aajisaka/fix-iv. Closes #7374 abfe628 [Akira Ajisaka] Throw IllegalArgumentException for malformed tokens. Specify UTF-8 charset 96351c8 [Akira Ajisaka] Move random into object f5a840b [Akira Ajisaka] Fix static zero IV in InternalSecurityAccessor Authored-by: Akira Ajisaka <aajisaka@apache.org> Signed-off-by: Akira Ajisaka <aajisaka@apache.org>
1 parent 3a529eb commit f9f0b1a

File tree

1 file changed

+20
-13
lines changed

1 file changed

+20
-13
lines changed

kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/InternalSecurityAccessor.scala

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
package org.apache.kyuubi.service.authentication
1919

20+
import java.nio.charset.StandardCharsets
21+
import java.security.SecureRandom
2022
import javax.crypto.Cipher
2123
import javax.crypto.spec.{IvParameterSpec, SecretKeySpec}
2224

@@ -34,21 +36,15 @@ class InternalSecurityAccessor(conf: KyuubiConf, val isServer: Boolean) {
3436

3537
private val tokenMaxLifeTime: Long = conf.get(ENGINE_SECURITY_TOKEN_MAX_LIFETIME)
3638
private val provider: EngineSecuritySecretProvider = EngineSecuritySecretProvider.create(conf)
37-
private val (encryptor, decryptor) =
39+
private val (secretKeySpec, encryptor, decryptor) =
3840
initializeForAuth(cryptoCipher, normalizeSecret(provider.getSecret()))
3941

40-
private def initializeForAuth(cipher: String, secret: String): (Cipher, Cipher) = {
41-
val secretKeySpec = new SecretKeySpec(secret.getBytes, cryptoKeyAlgorithm)
42-
val nonce = new Array[Byte](cryptoIvLength)
43-
val iv = new IvParameterSpec(nonce)
44-
42+
private def initializeForAuth(cipher: String, secret: String): (SecretKeySpec, Cipher, Cipher) = {
43+
val secretKeySpec =
44+
new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), cryptoKeyAlgorithm)
4545
val _encryptor = Cipher.getInstance(cipher)
46-
_encryptor.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv)
47-
4846
val _decryptor = Cipher.getInstance(cipher)
49-
_decryptor.init(Cipher.DECRYPT_MODE, secretKeySpec, iv)
50-
51-
(_encryptor, _decryptor)
47+
(secretKeySpec, _encryptor, _decryptor)
5248
}
5349

5450
def issueToken(): String = {
@@ -69,11 +65,21 @@ class InternalSecurityAccessor(conf: KyuubiConf, val isServer: Boolean) {
6965
}
7066

7167
private[authentication] def encrypt(value: String): String = synchronized {
72-
byteArrayToHexString(encryptor.doFinal(value.getBytes))
68+
val nonce = new Array[Byte](cryptoIvLength)
69+
InternalSecurityAccessor.random.nextBytes(nonce)
70+
encryptor.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(nonce))
71+
byteArrayToHexString(nonce ++ encryptor.doFinal(value.getBytes(StandardCharsets.UTF_8)))
7372
}
7473

7574
private[authentication] def decrypt(value: String): String = synchronized {
76-
new String(decryptor.doFinal(hexStringToByteArray(value)))
75+
val bytes = hexStringToByteArray(value)
76+
if (bytes.length <= cryptoIvLength) {
77+
throw new IllegalArgumentException(
78+
"Malformed engine access token: ciphertext is shorter than the IV length")
79+
}
80+
val nonce = bytes.take(cryptoIvLength)
81+
decryptor.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(nonce))
82+
new String(decryptor.doFinal(bytes.drop(cryptoIvLength)), StandardCharsets.UTF_8)
7783
}
7884

7985
private def normalizeSecret(secret: String): String = {
@@ -113,6 +119,7 @@ class InternalSecurityAccessor(conf: KyuubiConf, val isServer: Boolean) {
113119

114120
object InternalSecurityAccessor extends Logging {
115121
@volatile private var _engineSecurityAccessor: InternalSecurityAccessor = _
122+
private val random: SecureRandom = new SecureRandom()
116123

117124
def initialize(conf: KyuubiConf, isServer: Boolean): Unit = {
118125
if (_engineSecurityAccessor == null) {

0 commit comments

Comments
 (0)