Update SOGS signature construction

This commit is contained in:
ceokot 2022-03-31 07:41:56 +02:00
parent b51013f050
commit 301fe537e4
4 changed files with 53 additions and 35 deletions

View File

@ -8,7 +8,7 @@ import org.hamcrest.MatcherAssert.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.session.libsession.messaging.utilities.SodiumUtilities
import org.session.libsignal.utilities.toHexString
import org.session.libsignal.utilities.Base64
@RunWith(AndroidJUnit4::class)
class SodiumUtilitiesTest {
@ -26,27 +26,25 @@ class SodiumUtilitiesTest {
assertThat(keyPair.publicKey.asHexString.lowercase(), equalTo(blindedKey))
}
@Test
fun sharedBlindedEncryptionKey() {
val key = ByteArray(0)
val encryptionKey = SodiumUtilities.sharedBlindedEncryptionKey(key, key, key, key)
}
@Test
fun sogsSignature() {
// val expectedSignature = "K1N3A+H4dxV/wiN6Mr9cEj9TWUUqxESDoGW1cmoqDp7zMzCuCraTQKPX1tIiPuOBmFvB8VSUuYsHZrfGis1hDA=="
// val expectedSignature = "xxLpXHbomAJMB9AtGMyqvBsXrdd2040y+Ol/IKzElWfKJa3EYZRv1GLO6CTLhrDFUwVQe8PPltyGs54Kd7O5Cg=="
val expectedSignature = "gYqpWZX6fnF4Gb2xQM3xaXs0WIYEI49+B8q4mUUEg8Rw0ObaHUWfoWjMHMArAtP9QlORfiydsKWz1o6zdPVeCQ=="
val expectedSignature = "K1N3A+H4dxV/wiN6Mr9cEj9TWUUqxESDoGW1cmoqDp7zMzCuCraTQKPX1tIiPuOBmFvB8VSUuYsHZrfGis1hDA=="
val keyPair = SodiumUtilities.blindedKeyPair(serverPublicKey, KeyPair(pubKey, secKey))!!
val signature = SodiumUtilities.sogsSignature(
ByteArray(0),
val message = serverPublicKey.toByteArray()
.plus(Base64.decode("CaLsVaBSL9jarS5SwzJd8g=="))
.plus("1647896537".toByteArray(Charsets.US_ASCII))
.plus("GET".toByteArray())
.plus("/room/sudoku/messages/recent?limit=25".toByteArray())
.plus(ByteArray(0))
val signature = Base64.encodeBytes(SodiumUtilities.sogsSignature(
message,
secKey.asBytes,
keyPair.secretKey.asBytes,
keyPair.publicKey.asBytes
)!!
)!!)
assertThat(signature.toHexString(), equalTo(expectedSignature))
assertThat(signature, equalTo(expectedSignature))
}
}

View File

@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.annotation.JsonNaming
import com.fasterxml.jackson.databind.type.TypeFactory
import com.goterl.lazysodium.LazySodiumAndroid
import com.goterl.lazysodium.SodiumAndroid
import com.goterl.lazysodium.interfaces.GenericHash
import kotlinx.coroutines.flow.MutableSharedFlow
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.functional.bind
@ -153,8 +154,27 @@ object OpenGroupApiV4 {
SodiumUtilities.IdPrefix.BLINDED,
keyPair.publicKey.asBytes
).hexString
var bodyHash = ByteArray(0)
if (request.parameters != null) {
val parameterBytes = JsonUtil.toJson(request.parameters).toByteArray()
val parameterHash = ByteArray(GenericHash.BYTES_MAX)
if (sodium.cryptoGenericHash(
parameterHash,
parameterHash.size,
parameterBytes,
parameterBytes.size.toLong()
)) {
bodyHash = parameterHash
}
}
val messageBytes = publicKey.toByteArray()
.plus(nonce)
.plus("$timestamp".toByteArray(Charsets.US_ASCII))
.plus(request.verb.rawValue.toByteArray())
.plus(urlRequest.url().toString().toByteArray())
.plus(bodyHash)
signature = SodiumUtilities.sogsSignature(
urlRequest.toString().toByteArray(),
messageBytes,
ed25519KeyPair.secretKey.asBytes,
keyPair.secretKey.asBytes,
keyPair.publicKey.asBytes
@ -630,7 +650,8 @@ object OpenGroupApiV4 {
room = null,
server = server,
endpoint = "rooms",
isAuthRequired = false
isAuthRequired = false,
isBlinded = true
)
return send(request).map { json ->
val rawRooms = json["rooms"] as? List<Map<*, *>> ?: throw Error.ParsingFailed

View File

@ -3,7 +3,6 @@ package org.session.libsession.messaging.utilities
import com.goterl.lazysodium.LazySodiumAndroid
import com.goterl.lazysodium.SodiumAndroid
import com.goterl.lazysodium.interfaces.GenericHash
import com.goterl.lazysodium.interfaces.Hash
import com.goterl.lazysodium.interfaces.Sign
import com.goterl.lazysodium.utils.Key
import com.goterl.lazysodium.utils.KeyPair
@ -47,8 +46,8 @@ object SodiumUtilities {
/* Constructs a "blinded" key pair (`ka, kA`) based on an open group server `publicKey` and an ed25519 `keyPair` */
fun blindedKeyPair(serverPublicKey: String, edKeyPair: KeyPair): KeyPair? {
if (edKeyPair.publicKey.asBytes.size != Sign.PUBLICKEYBYTES ||
edKeyPair.secretKey.asBytes.size != Sign.SECRETKEYBYTES) return null
// if (edKeyPair.publicKey.asBytes.size != Sign.PUBLICKEYBYTES ||
// edKeyPair.secretKey.asBytes.size != Sign.SECRETKEYBYTES) return null
val kBytes = generateBlindingFactor(serverPublicKey)
val aBytes = generatePrivateKeyScalar(edKeyPair.secretKey.asBytes)
// Generate the blinded key pair `ka`, `kA`
@ -74,16 +73,16 @@ object SodiumUtilities {
fun sogsSignature(
message: ByteArray,
secretKey: ByteArray,
ka: ByteArray, /*blindedSecretKey*/
kA: ByteArray /*blindedPublicKey*/
blindedSecretKey: ByteArray, /*ka*/
blindedPublicKey: ByteArray /*kA*/
): ByteArray? {
// H_rh = sha512(s.encode()).digest()[32:]
val h_rh = ByteArray(Hash.SHA512_BYTES)
val h_rh = ByteArray(GenericHash.BYTES)
if (!sodium.cryptoHashSha512(h_rh, secretKey, secretKey.size.toLong())) return null
// r = salt.crypto_core_ed25519_scalar_reduce(sha512_multipart(H_rh, kA, message_parts))
val combinedData = h_rh + kA + message
val combinedHash = ByteArray(Hash.SHA512_BYTES)
val combinedData = h_rh + blindedPublicKey + message
val combinedHash = ByteArray(GenericHash.BYTES)
if (!sodium.cryptoHashSha512(combinedHash, combinedData, combinedData.size.toLong())) return null
val rHash = ByteArray(Sign.CURVE25519_PUBLICKEYBYTES)
sodium.cryptoCoreEd25519ScalarReduce(rHash, combinedHash)
@ -92,23 +91,23 @@ object SodiumUtilities {
}
// sig_R = salt.crypto_scalarmult_ed25519_base_noclamp(r)
val sig_R = ByteArray(Sign.SECRETKEYBYTES)
val sig_R = ByteArray(Sign.ED25519_PUBLICKEYBYTES)
if (!sodium.cryptoScalarMultBase(sig_R, rHash)) return null
// HRAM = salt.crypto_core_ed25519_scalar_reduce(sha512_multipart(sig_R, kA, message_parts))
val hRamData = sig_R + kA + message
val hRamHash = ByteArray(Hash.SHA512_BYTES)
val hRamData = sig_R + blindedPublicKey + message
val hRamHash = ByteArray(GenericHash.BYTES)
if (!sodium.cryptoHashSha512(hRamHash, hRamData, hRamData.size.toLong())) return null
val hRam = ByteArray(Sign.CURVE25519_PUBLICKEYBYTES)
val hRam = ByteArray(Sign.ED25519_PUBLICKEYBYTES)
sodium.cryptoCoreEd25519ScalarReduce(hRam, hRamHash)
if (hRam.all { it.toInt() == 0 }) {
return null
}
// sig_s = salt.crypto_core_ed25519_scalar_add(r, salt.crypto_core_ed25519_scalar_mul(HRAM, ka))
val sig_sMul = ByteArray(Sign.CURVE25519_PUBLICKEYBYTES)
val sig_s = ByteArray(Sign.CURVE25519_PUBLICKEYBYTES)
if (sodium.cryptoScalarMult(sig_sMul, hRam, ka)) {
sodium.cryptoCoreEd25519ScalarReduce(sig_s/*, rHash*/, sig_sMul)
val sig_sMul = ByteArray(Sign.ED25519_PUBLICKEYBYTES)
val sig_s = ByteArray(Sign.ED25519_PUBLICKEYBYTES)
if (sodium.cryptoScalarMult(sig_sMul, hRam, blindedSecretKey)) {
sodium.cryptoCoreEd25519ScalarAdd(sig_s, rHash, sig_sMul)
} else return null
return sig_R + sig_s

View File

@ -490,14 +490,14 @@ object OnionRequestAPI {
"headers" to headers
)
val requestData = JsonUtil.toJson(requestPayload).toByteArray()
val prefixData = "l${requestData.size}".toByteArray()
val suffixData = "e".toByteArray()
val prefixData = "l${requestData.size}".toByteArray(Charsets.US_ASCII)
val suffixData = "e".toByteArray(Charsets.US_ASCII)
if (request.body() != null) {
val bodyPayload = mapOf(
"body" to body
)
val bodyData = JsonUtil.toJson(bodyPayload).toByteArray()
val bodyLengthData = "${bodyData.size}".toByteArray()
val bodyLengthData = "${bodyData.size}".toByteArray(Charsets.US_ASCII)
prefixData + requestData + bodyLengthData + bodyData + suffixData
} else {
prefixData + requestData + suffixData