mirror of
https://github.com/oxen-io/session-android.git
synced 2025-04-24 18:51:28 +00:00
Update SOGS signature construction
This commit is contained in:
parent
b51013f050
commit
301fe537e4
@ -8,7 +8,7 @@ import org.hamcrest.MatcherAssert.assertThat
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.session.libsession.messaging.utilities.SodiumUtilities
|
import org.session.libsession.messaging.utilities.SodiumUtilities
|
||||||
import org.session.libsignal.utilities.toHexString
|
import org.session.libsignal.utilities.Base64
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class SodiumUtilitiesTest {
|
class SodiumUtilitiesTest {
|
||||||
@ -26,27 +26,25 @@ class SodiumUtilitiesTest {
|
|||||||
assertThat(keyPair.publicKey.asHexString.lowercase(), equalTo(blindedKey))
|
assertThat(keyPair.publicKey.asHexString.lowercase(), equalTo(blindedKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun sharedBlindedEncryptionKey() {
|
|
||||||
val key = ByteArray(0)
|
|
||||||
val encryptionKey = SodiumUtilities.sharedBlindedEncryptionKey(key, key, key, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun sogsSignature() {
|
fun sogsSignature() {
|
||||||
// val expectedSignature = "K1N3A+H4dxV/wiN6Mr9cEj9TWUUqxESDoGW1cmoqDp7zMzCuCraTQKPX1tIiPuOBmFvB8VSUuYsHZrfGis1hDA=="
|
val expectedSignature = "K1N3A+H4dxV/wiN6Mr9cEj9TWUUqxESDoGW1cmoqDp7zMzCuCraTQKPX1tIiPuOBmFvB8VSUuYsHZrfGis1hDA=="
|
||||||
// val expectedSignature = "xxLpXHbomAJMB9AtGMyqvBsXrdd2040y+Ol/IKzElWfKJa3EYZRv1GLO6CTLhrDFUwVQe8PPltyGs54Kd7O5Cg=="
|
|
||||||
val expectedSignature = "gYqpWZX6fnF4Gb2xQM3xaXs0WIYEI49+B8q4mUUEg8Rw0ObaHUWfoWjMHMArAtP9QlORfiydsKWz1o6zdPVeCQ=="
|
|
||||||
val keyPair = SodiumUtilities.blindedKeyPair(serverPublicKey, KeyPair(pubKey, secKey))!!
|
val keyPair = SodiumUtilities.blindedKeyPair(serverPublicKey, KeyPair(pubKey, secKey))!!
|
||||||
|
|
||||||
val signature = SodiumUtilities.sogsSignature(
|
val message = serverPublicKey.toByteArray()
|
||||||
ByteArray(0),
|
.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,
|
secKey.asBytes,
|
||||||
keyPair.secretKey.asBytes,
|
keyPair.secretKey.asBytes,
|
||||||
keyPair.publicKey.asBytes
|
keyPair.publicKey.asBytes
|
||||||
)!!
|
)!!)
|
||||||
|
|
||||||
assertThat(signature.toHexString(), equalTo(expectedSignature))
|
assertThat(signature, equalTo(expectedSignature))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.annotation.JsonNaming
|
|||||||
import com.fasterxml.jackson.databind.type.TypeFactory
|
import com.fasterxml.jackson.databind.type.TypeFactory
|
||||||
import com.goterl.lazysodium.LazySodiumAndroid
|
import com.goterl.lazysodium.LazySodiumAndroid
|
||||||
import com.goterl.lazysodium.SodiumAndroid
|
import com.goterl.lazysodium.SodiumAndroid
|
||||||
|
import com.goterl.lazysodium.interfaces.GenericHash
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import nl.komponents.kovenant.Promise
|
import nl.komponents.kovenant.Promise
|
||||||
import nl.komponents.kovenant.functional.bind
|
import nl.komponents.kovenant.functional.bind
|
||||||
@ -153,8 +154,27 @@ object OpenGroupApiV4 {
|
|||||||
SodiumUtilities.IdPrefix.BLINDED,
|
SodiumUtilities.IdPrefix.BLINDED,
|
||||||
keyPair.publicKey.asBytes
|
keyPair.publicKey.asBytes
|
||||||
).hexString
|
).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(
|
signature = SodiumUtilities.sogsSignature(
|
||||||
urlRequest.toString().toByteArray(),
|
messageBytes,
|
||||||
ed25519KeyPair.secretKey.asBytes,
|
ed25519KeyPair.secretKey.asBytes,
|
||||||
keyPair.secretKey.asBytes,
|
keyPair.secretKey.asBytes,
|
||||||
keyPair.publicKey.asBytes
|
keyPair.publicKey.asBytes
|
||||||
@ -630,7 +650,8 @@ object OpenGroupApiV4 {
|
|||||||
room = null,
|
room = null,
|
||||||
server = server,
|
server = server,
|
||||||
endpoint = "rooms",
|
endpoint = "rooms",
|
||||||
isAuthRequired = false
|
isAuthRequired = false,
|
||||||
|
isBlinded = true
|
||||||
)
|
)
|
||||||
return send(request).map { json ->
|
return send(request).map { json ->
|
||||||
val rawRooms = json["rooms"] as? List<Map<*, *>> ?: throw Error.ParsingFailed
|
val rawRooms = json["rooms"] as? List<Map<*, *>> ?: throw Error.ParsingFailed
|
||||||
|
@ -3,7 +3,6 @@ package org.session.libsession.messaging.utilities
|
|||||||
import com.goterl.lazysodium.LazySodiumAndroid
|
import com.goterl.lazysodium.LazySodiumAndroid
|
||||||
import com.goterl.lazysodium.SodiumAndroid
|
import com.goterl.lazysodium.SodiumAndroid
|
||||||
import com.goterl.lazysodium.interfaces.GenericHash
|
import com.goterl.lazysodium.interfaces.GenericHash
|
||||||
import com.goterl.lazysodium.interfaces.Hash
|
|
||||||
import com.goterl.lazysodium.interfaces.Sign
|
import com.goterl.lazysodium.interfaces.Sign
|
||||||
import com.goterl.lazysodium.utils.Key
|
import com.goterl.lazysodium.utils.Key
|
||||||
import com.goterl.lazysodium.utils.KeyPair
|
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` */
|
/* 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? {
|
fun blindedKeyPair(serverPublicKey: String, edKeyPair: KeyPair): KeyPair? {
|
||||||
if (edKeyPair.publicKey.asBytes.size != Sign.PUBLICKEYBYTES ||
|
// if (edKeyPair.publicKey.asBytes.size != Sign.PUBLICKEYBYTES ||
|
||||||
edKeyPair.secretKey.asBytes.size != Sign.SECRETKEYBYTES) return null
|
// edKeyPair.secretKey.asBytes.size != Sign.SECRETKEYBYTES) return null
|
||||||
val kBytes = generateBlindingFactor(serverPublicKey)
|
val kBytes = generateBlindingFactor(serverPublicKey)
|
||||||
val aBytes = generatePrivateKeyScalar(edKeyPair.secretKey.asBytes)
|
val aBytes = generatePrivateKeyScalar(edKeyPair.secretKey.asBytes)
|
||||||
// Generate the blinded key pair `ka`, `kA`
|
// Generate the blinded key pair `ka`, `kA`
|
||||||
@ -74,16 +73,16 @@ object SodiumUtilities {
|
|||||||
fun sogsSignature(
|
fun sogsSignature(
|
||||||
message: ByteArray,
|
message: ByteArray,
|
||||||
secretKey: ByteArray,
|
secretKey: ByteArray,
|
||||||
ka: ByteArray, /*blindedSecretKey*/
|
blindedSecretKey: ByteArray, /*ka*/
|
||||||
kA: ByteArray /*blindedPublicKey*/
|
blindedPublicKey: ByteArray /*kA*/
|
||||||
): ByteArray? {
|
): ByteArray? {
|
||||||
// H_rh = sha512(s.encode()).digest()[32:]
|
// 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
|
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))
|
// r = salt.crypto_core_ed25519_scalar_reduce(sha512_multipart(H_rh, kA, message_parts))
|
||||||
val combinedData = h_rh + kA + message
|
val combinedData = h_rh + blindedPublicKey + message
|
||||||
val combinedHash = ByteArray(Hash.SHA512_BYTES)
|
val combinedHash = ByteArray(GenericHash.BYTES)
|
||||||
if (!sodium.cryptoHashSha512(combinedHash, combinedData, combinedData.size.toLong())) return null
|
if (!sodium.cryptoHashSha512(combinedHash, combinedData, combinedData.size.toLong())) return null
|
||||||
val rHash = ByteArray(Sign.CURVE25519_PUBLICKEYBYTES)
|
val rHash = ByteArray(Sign.CURVE25519_PUBLICKEYBYTES)
|
||||||
sodium.cryptoCoreEd25519ScalarReduce(rHash, combinedHash)
|
sodium.cryptoCoreEd25519ScalarReduce(rHash, combinedHash)
|
||||||
@ -92,23 +91,23 @@ object SodiumUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sig_R = salt.crypto_scalarmult_ed25519_base_noclamp(r)
|
// 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
|
if (!sodium.cryptoScalarMultBase(sig_R, rHash)) return null
|
||||||
|
|
||||||
// HRAM = salt.crypto_core_ed25519_scalar_reduce(sha512_multipart(sig_R, kA, message_parts))
|
// HRAM = salt.crypto_core_ed25519_scalar_reduce(sha512_multipart(sig_R, kA, message_parts))
|
||||||
val hRamData = sig_R + kA + message
|
val hRamData = sig_R + blindedPublicKey + message
|
||||||
val hRamHash = ByteArray(Hash.SHA512_BYTES)
|
val hRamHash = ByteArray(GenericHash.BYTES)
|
||||||
if (!sodium.cryptoHashSha512(hRamHash, hRamData, hRamData.size.toLong())) return null
|
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)
|
sodium.cryptoCoreEd25519ScalarReduce(hRam, hRamHash)
|
||||||
if (hRam.all { it.toInt() == 0 }) {
|
if (hRam.all { it.toInt() == 0 }) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
// sig_s = salt.crypto_core_ed25519_scalar_add(r, salt.crypto_core_ed25519_scalar_mul(HRAM, ka))
|
// 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_sMul = ByteArray(Sign.ED25519_PUBLICKEYBYTES)
|
||||||
val sig_s = ByteArray(Sign.CURVE25519_PUBLICKEYBYTES)
|
val sig_s = ByteArray(Sign.ED25519_PUBLICKEYBYTES)
|
||||||
if (sodium.cryptoScalarMult(sig_sMul, hRam, ka)) {
|
if (sodium.cryptoScalarMult(sig_sMul, hRam, blindedSecretKey)) {
|
||||||
sodium.cryptoCoreEd25519ScalarReduce(sig_s/*, rHash*/, sig_sMul)
|
sodium.cryptoCoreEd25519ScalarAdd(sig_s, rHash, sig_sMul)
|
||||||
} else return null
|
} else return null
|
||||||
|
|
||||||
return sig_R + sig_s
|
return sig_R + sig_s
|
||||||
|
@ -490,14 +490,14 @@ object OnionRequestAPI {
|
|||||||
"headers" to headers
|
"headers" to headers
|
||||||
)
|
)
|
||||||
val requestData = JsonUtil.toJson(requestPayload).toByteArray()
|
val requestData = JsonUtil.toJson(requestPayload).toByteArray()
|
||||||
val prefixData = "l${requestData.size}".toByteArray()
|
val prefixData = "l${requestData.size}".toByteArray(Charsets.US_ASCII)
|
||||||
val suffixData = "e".toByteArray()
|
val suffixData = "e".toByteArray(Charsets.US_ASCII)
|
||||||
if (request.body() != null) {
|
if (request.body() != null) {
|
||||||
val bodyPayload = mapOf(
|
val bodyPayload = mapOf(
|
||||||
"body" to body
|
"body" to body
|
||||||
)
|
)
|
||||||
val bodyData = JsonUtil.toJson(bodyPayload).toByteArray()
|
val bodyData = JsonUtil.toJson(bodyPayload).toByteArray()
|
||||||
val bodyLengthData = "${bodyData.size}".toByteArray()
|
val bodyLengthData = "${bodyData.size}".toByteArray(Charsets.US_ASCII)
|
||||||
prefixData + requestData + bodyLengthData + bodyData + suffixData
|
prefixData + requestData + bodyLengthData + bodyData + suffixData
|
||||||
} else {
|
} else {
|
||||||
prefixData + requestData + suffixData
|
prefixData + requestData + suffixData
|
||||||
|
Loading…
x
Reference in New Issue
Block a user