All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.at.asitplus.wallet.lib.aries.MessageWrapper.kt Maven / Gradle / Ivy

package at.asitplus.wallet.lib.aries

import at.asitplus.KmmResult
import at.asitplus.crypto.datatypes.jws.JsonWebKey
import at.asitplus.crypto.datatypes.jws.JweAlgorithm
import at.asitplus.crypto.datatypes.jws.JweEncrypted
import at.asitplus.crypto.datatypes.jws.JweEncryption
import at.asitplus.crypto.datatypes.jws.JwsSigned
import at.asitplus.crypto.datatypes.jws.toJsonWebKey
import at.asitplus.wallet.lib.agent.CryptoService
import at.asitplus.wallet.lib.jws.DefaultJwsService
import at.asitplus.wallet.lib.jws.DefaultVerifierJwsService
import at.asitplus.wallet.lib.jws.JwsContentTypeConstants
import at.asitplus.wallet.lib.jws.JwsService
import at.asitplus.wallet.lib.jws.VerifierJwsService
import at.asitplus.wallet.lib.msg.JsonWebMessage
import io.github.aakira.napier.Napier

class MessageWrapper(
    private val cryptoService: CryptoService,
    private val jwsService: JwsService = DefaultJwsService(cryptoService),
    private val verifierJwsService: VerifierJwsService = DefaultVerifierJwsService(),
) {

    suspend fun parseMessage(it: String): ReceivedMessage {
        val jwsSigned = JwsSigned.parse(it).getOrNull()
        if (jwsSigned != null) {
            return parseJwsMessage(jwsSigned, it)
        }
        val jweEncrypted = JweEncrypted.parse(it).getOrNull()
        if (jweEncrypted != null)
            return parseJweMessage(jweEncrypted, it)
        return ReceivedMessage.Error
            .also { Napier.w("Could not parse message: $it") }
    }

    private suspend fun parseJweMessage(
        jweObject: JweEncrypted,
        serialized: String
    ): ReceivedMessage {
        Napier.d("Parsing JWE ${jweObject.serialize()}")
        val joseObject = jwsService.decryptJweObject(jweObject, serialized).getOrElse {
            Napier.w("Could not parse JWE", it)
            return ReceivedMessage.Error
        }
        val payloadString = joseObject.payload.decodeToString()
        if (joseObject.header.contentType == JwsContentTypeConstants.DIDCOMM_SIGNED_JSON) {
            val parsed = JwsSigned.parse(payloadString).getOrNull()
                ?: return ReceivedMessage.Error
                    .also { Napier.w("Could not parse inner JWS") }
            return parseJwsMessage(parsed, payloadString)
        }
        if (joseObject.header.contentType == JwsContentTypeConstants.DIDCOMM_PLAIN_JSON) {
            val message = JsonWebMessage.deserialize(payloadString).getOrElse { ex ->
                return ReceivedMessage.Error
                    .also { Napier.w("Could not parse plain message", ex) }
            }
            return ReceivedMessage.Success(message, joseObject.header.publicKey)
        }
        return ReceivedMessage.Error
            .also { Napier.w("ContentType not matching") }
    }

    private fun parseJwsMessage(joseObject: JwsSigned, serialized: String): ReceivedMessage {
        Napier.d("Parsing JWS ${joseObject.serialize()}")
        if (!verifierJwsService.verifyJwsObject(joseObject))
            return ReceivedMessage.Error
                .also { Napier.w("Signature invalid") }
        if (joseObject.header.contentType == JwsContentTypeConstants.DIDCOMM_PLAIN_JSON) {
            val payloadString = joseObject.payload.decodeToString()
            val message = JsonWebMessage.deserialize(payloadString).getOrElse { ex ->
                return ReceivedMessage.Error
                    .also { Napier.w("Could not parse plain message", ex) }
            }
            return ReceivedMessage.Success(message, joseObject.header.publicKey?.toJsonWebKey())
        }
        return ReceivedMessage.Error
            .also { Napier.w("ContentType not matching") }
    }

    suspend fun createSignedAndEncryptedJwe(jwm: JsonWebMessage, recipientKey: JsonWebKey): KmmResult {
        val jwt = createSignedJwt(jwm).getOrElse {
            Napier.w("Can not create signed JWT for encryption", it)
            return KmmResult.failure(it)
        }
        val jwe = jwsService.encryptJweObject(
            JwsContentTypeConstants.DIDCOMM_ENCRYPTED_JSON,
            jwt.serialize().encodeToByteArray(),
            recipientKey,
            JwsContentTypeConstants.DIDCOMM_SIGNED_JSON,
            JweAlgorithm.ECDH_ES,
            JweEncryption.A256GCM,
        ).getOrElse {
            return KmmResult.failure(it)
        }
        return KmmResult.success(jwe)
    }

    suspend fun createSignedJwt(jwm: JsonWebMessage): KmmResult = jwsService.createSignedJwt(
        JwsContentTypeConstants.DIDCOMM_SIGNED_JSON,
        jwm.serialize().encodeToByteArray(),
        JwsContentTypeConstants.DIDCOMM_PLAIN_JSON
    )

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy