diff --git a/voice/api/voice.api b/voice/api/voice.api index 2bdd226cdc1..2285ba5b51f 100644 --- a/voice/api/voice.api +++ b/voice/api/voice.api @@ -204,6 +204,14 @@ public abstract class dev/kord/voice/EncryptionMode { public final fun toString ()Ljava/lang/String; } +public final class dev/kord/voice/EncryptionMode$AeadAes256Gcm : dev/kord/voice/EncryptionMode { + public static final field INSTANCE Ldev/kord/voice/EncryptionMode$AeadAes256Gcm; +} + +public final class dev/kord/voice/EncryptionMode$AeadAes256GcmRtpSize : dev/kord/voice/EncryptionMode { + public static final field INSTANCE Ldev/kord/voice/EncryptionMode$AeadAes256GcmRtpSize; +} + public final class dev/kord/voice/EncryptionMode$Companion { public final fun from (Ljava/lang/String;)Ldev/kord/voice/EncryptionMode; public final fun getEntries ()Ljava/util/List; @@ -317,16 +325,16 @@ public final class dev/kord/voice/SpeakingFlags$Companion { } public final class dev/kord/voice/VoiceConnection { - public synthetic fun (Ldev/kord/voice/VoiceConnectionData;Ldev/kord/gateway/Gateway;Ldev/kord/voice/gateway/VoiceGateway;Ldev/kord/voice/udp/VoiceUdpSocket;Ldev/kord/voice/gateway/VoiceGatewayConfiguration;Ldev/kord/voice/streams/Streams;Ldev/kord/voice/AudioProvider;Ldev/kord/voice/FrameInterceptor;Ldev/kord/voice/udp/AudioFrameSender;Ldev/kord/voice/encryption/strategies/NonceStrategy;JLkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ldev/kord/voice/VoiceConnectionData;Ldev/kord/gateway/Gateway;Ldev/kord/voice/gateway/VoiceGateway;Ldev/kord/voice/udp/VoiceUdpSocket;Ldev/kord/voice/gateway/VoiceGatewayConfiguration;Ldev/kord/voice/streams/Streams;Ldev/kord/voice/AudioProvider;Ldev/kord/voice/FrameInterceptor;Ldev/kord/voice/udp/AudioFrameSender;Ldev/kord/voice/encryption/VoiceEncryption;JLkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun connect (Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun connect$default (Ldev/kord/voice/VoiceConnection;Lkotlinx/coroutines/CoroutineScope;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public final fun disconnect (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun getAudioProvider ()Ldev/kord/voice/AudioProvider; public final fun getData ()Ldev/kord/voice/VoiceConnectionData; + public final fun getEncryption ()Ldev/kord/voice/encryption/VoiceEncryption; public final fun getFrameInterceptor ()Ldev/kord/voice/FrameInterceptor; public final fun getFrameSender ()Ldev/kord/voice/udp/AudioFrameSender; public final fun getGateway ()Ldev/kord/gateway/Gateway; - public final fun getNonceStrategy ()Ldev/kord/voice/encryption/strategies/NonceStrategy; public final fun getScope ()Lkotlinx/coroutines/CoroutineScope; public final fun getSocket ()Ldev/kord/voice/udp/VoiceUdpSocket; public final fun getStreams ()Ldev/kord/voice/streams/Streams; @@ -348,10 +356,10 @@ public final class dev/kord/voice/VoiceConnectionBuilder { public final fun getAudioSender ()Ldev/kord/voice/udp/AudioFrameSender; public final fun getChannelId ()Ldev/kord/common/entity/Snowflake; public final fun getConnectionDetachDuration-UwyO8pc ()J + public final fun getEncryption ()Ldev/kord/voice/encryption/VoiceEncryption; public final fun getFrameInterceptor ()Ldev/kord/voice/FrameInterceptor; public final fun getGateway ()Ldev/kord/gateway/Gateway; public final fun getGuildId ()Ldev/kord/common/entity/Snowflake; - public final fun getNonceStrategy ()Ldev/kord/voice/encryption/strategies/NonceStrategy; public final fun getReceiveVoice ()Z public final fun getSelfDeaf ()Z public final fun getSelfId ()Ldev/kord/common/entity/Snowflake; @@ -363,10 +371,10 @@ public final class dev/kord/voice/VoiceConnectionBuilder { public final fun setAudioSender (Ldev/kord/voice/udp/AudioFrameSender;)V public final fun setChannelId (Ldev/kord/common/entity/Snowflake;)V public final fun setConnectionDetachDuration-LRDsOJo (J)V + public final fun setEncryption (Ldev/kord/voice/encryption/VoiceEncryption;)V public final fun setFrameInterceptor (Ldev/kord/voice/FrameInterceptor;)V public final fun setGateway (Ldev/kord/gateway/Gateway;)V public final fun setGuildId (Ldev/kord/common/entity/Snowflake;)V - public final fun setNonceStrategy (Ldev/kord/voice/encryption/strategies/NonceStrategy;)V public final fun setReceiveVoice (Z)V public final fun setSelfDeaf (Z)V public final fun setSelfId (Ldev/kord/common/entity/Snowflake;)V @@ -397,53 +405,135 @@ public final class dev/kord/voice/VoiceConnectionKt { public static synthetic fun VoiceConnection$default (Ldev/kord/gateway/Gateway;Ldev/kord/common/entity/Snowflake;Ldev/kord/common/entity/Snowflake;Ldev/kord/common/entity/Snowflake;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; } -public final class dev/kord/voice/encryption/XSalsa20Poly1305Codec { - public fun ([B)V - public final fun decrypt ([BII[BLdev/kord/voice/io/MutableByteArrayCursor;)Z - public static synthetic fun decrypt$default (Ldev/kord/voice/encryption/XSalsa20Poly1305Codec;[BII[BLdev/kord/voice/io/MutableByteArrayCursor;ILjava/lang/Object;)Z - public final fun encrypt ([BII[BLdev/kord/voice/io/MutableByteArrayCursor;)Z - public static synthetic fun encrypt$default (Ldev/kord/voice/encryption/XSalsa20Poly1305Codec;[BII[BLdev/kord/voice/io/MutableByteArrayCursor;ILjava/lang/Object;)Z - public final fun getKey ()[B +public final class dev/kord/voice/encryption/AeadAes256Gcm : dev/kord/voice/encryption/VoiceEncryption { + public static final field INSTANCE Ldev/kord/voice/encryption/AeadAes256Gcm; + public fun createBox ([B)Ldev/kord/voice/encryption/VoiceEncryption$Box; + public fun createUnbox ([B)Ldev/kord/voice/encryption/VoiceEncryption$Unbox; + public fun equals (Ljava/lang/Object;)Z + public fun getMode ()Ldev/kord/voice/EncryptionMode; + public fun getNonceLength ()I + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public abstract interface class dev/kord/voice/encryption/VoiceEncryption { + public abstract fun createBox ([B)Ldev/kord/voice/encryption/VoiceEncryption$Box; + public abstract fun createUnbox ([B)Ldev/kord/voice/encryption/VoiceEncryption$Unbox; + public abstract fun getMode ()Ldev/kord/voice/EncryptionMode; + public abstract fun getNonceLength ()I +} + +public abstract interface class dev/kord/voice/encryption/VoiceEncryption$Box : dev/kord/voice/encryption/VoiceEncryption$Method { + public abstract fun appendNonce (Ldev/kord/voice/io/ByteArrayView;Ldev/kord/voice/io/MutableByteArrayCursor;)V + public abstract fun generateNonce (Lkotlin/jvm/functions/Function0;)Ldev/kord/voice/io/ByteArrayView; + public abstract fun getOverhead ()I +} + +public abstract interface class dev/kord/voice/encryption/VoiceEncryption$Method { + public abstract fun apply (Ldev/kord/voice/io/ByteArrayView;Ldev/kord/voice/io/MutableByteArrayCursor;Ldev/kord/voice/io/ByteArrayView;[B)Z +} + +public abstract interface class dev/kord/voice/encryption/VoiceEncryption$Unbox : dev/kord/voice/encryption/VoiceEncryption$Method { + public abstract fun getNonce (Ldev/kord/voice/udp/RTPPacket;)Ldev/kord/voice/io/ByteArrayView; +} + +public final class dev/kord/voice/encryption/XSalsa20Poly1305 : dev/kord/voice/encryption/VoiceEncryption { + public static final field Companion Ldev/kord/voice/encryption/XSalsa20Poly1305$Companion; + public fun ()V + public fun (Ldev/kord/voice/encryption/strategies/NonceStrategy$Factory;)V + public synthetic fun (Ldev/kord/voice/encryption/strategies/NonceStrategy$Factory;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ldev/kord/voice/encryption/strategies/NonceStrategy$Factory; + public final fun copy (Ldev/kord/voice/encryption/strategies/NonceStrategy$Factory;)Ldev/kord/voice/encryption/XSalsa20Poly1305; + public static synthetic fun copy$default (Ldev/kord/voice/encryption/XSalsa20Poly1305;Ldev/kord/voice/encryption/strategies/NonceStrategy$Factory;ILjava/lang/Object;)Ldev/kord/voice/encryption/XSalsa20Poly1305; + public fun createBox ([B)Ldev/kord/voice/encryption/VoiceEncryption$Box; + public fun createUnbox ([B)Ldev/kord/voice/encryption/VoiceEncryption$Unbox; + public fun equals (Ljava/lang/Object;)Z + public fun getMode ()Ldev/kord/voice/EncryptionMode; + public fun getNonceLength ()I + public final fun getNonceStrategyFactory ()Ldev/kord/voice/encryption/strategies/NonceStrategy$Factory; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class dev/kord/voice/encryption/XSalsa20Poly1305$Companion { } -public final class dev/kord/voice/encryption/XSalsa20Poly1305CodecKt { - public static final fun decrypt (Ldev/kord/voice/encryption/XSalsa20Poly1305Codec;[BII[B)[B - public static synthetic fun decrypt$default (Ldev/kord/voice/encryption/XSalsa20Poly1305Codec;[BII[BILjava/lang/Object;)[B - public static final fun encrypt (Ldev/kord/voice/encryption/XSalsa20Poly1305Codec;[BII[B)[B - public static synthetic fun encrypt$default (Ldev/kord/voice/encryption/XSalsa20Poly1305Codec;[BII[BILjava/lang/Object;)[B +public abstract class dev/kord/voice/encryption/XSalsa20Poly1305$Impl { + public synthetic fun (Ldev/kord/voice/encryption/strategies/NonceStrategy$Factory;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + protected final fun getC ()[B + protected final fun getM ()[B + protected final fun getNonceStrategy ()Ldev/kord/voice/encryption/strategies/NonceStrategy; + protected final fun getNonceStrategyFactory ()Ldev/kord/voice/encryption/strategies/NonceStrategy$Factory; +} + +public final class dev/kord/voice/encryption/XSalsa20Poly1305$Impl$Box : dev/kord/voice/encryption/XSalsa20Poly1305$Impl, dev/kord/voice/encryption/VoiceEncryption$Box { + public fun ([BLdev/kord/voice/encryption/strategies/NonceStrategy$Factory;)V + public fun appendNonce (Ldev/kord/voice/io/ByteArrayView;Ldev/kord/voice/io/MutableByteArrayCursor;)V + public fun apply (Ldev/kord/voice/io/ByteArrayView;Ldev/kord/voice/io/MutableByteArrayCursor;Ldev/kord/voice/io/ByteArrayView;[B)Z + public fun generateNonce (Lkotlin/jvm/functions/Function0;)Ldev/kord/voice/io/ByteArrayView; + public fun getOverhead ()I +} + +public final class dev/kord/voice/encryption/XSalsa20Poly1305$Impl$Unbox : dev/kord/voice/encryption/XSalsa20Poly1305$Impl, dev/kord/voice/encryption/VoiceEncryption$Unbox { + public fun ([BLdev/kord/voice/encryption/strategies/NonceStrategy$Factory;)V + public fun apply (Ldev/kord/voice/io/ByteArrayView;Ldev/kord/voice/io/MutableByteArrayCursor;Ldev/kord/voice/io/ByteArrayView;[B)Z + public fun getNonce (Ldev/kord/voice/udp/RTPPacket;)Ldev/kord/voice/io/ByteArrayView; } public final class dev/kord/voice/encryption/strategies/LiteNonceStrategy : dev/kord/voice/encryption/strategies/NonceStrategy { + public static final field Factory Ldev/kord/voice/encryption/strategies/LiteNonceStrategy$Factory; public fun ()V public fun append (Ldev/kord/voice/io/ByteArrayView;Ldev/kord/voice/io/MutableByteArrayCursor;)V public fun generate (Lkotlin/jvm/functions/Function0;)Ldev/kord/voice/io/ByteArrayView; - public fun getNonceLength ()I public fun strip (Ldev/kord/voice/udp/RTPPacket;)Ldev/kord/voice/io/ByteArrayView; } +public final class dev/kord/voice/encryption/strategies/LiteNonceStrategy$Factory : dev/kord/voice/encryption/strategies/NonceStrategy$Factory { + public fun create ()Ldev/kord/voice/encryption/strategies/NonceStrategy; + public fun getLength ()I + public fun getMode ()Ldev/kord/voice/EncryptionMode; +} + public abstract interface class dev/kord/voice/encryption/strategies/NonceStrategy { public abstract fun append (Ldev/kord/voice/io/ByteArrayView;Ldev/kord/voice/io/MutableByteArrayCursor;)V public abstract fun generate (Lkotlin/jvm/functions/Function0;)Ldev/kord/voice/io/ByteArrayView; - public abstract fun getNonceLength ()I public abstract fun strip (Ldev/kord/voice/udp/RTPPacket;)Ldev/kord/voice/io/ByteArrayView; } +public abstract interface class dev/kord/voice/encryption/strategies/NonceStrategy$Factory { + public abstract fun create ()Ldev/kord/voice/encryption/strategies/NonceStrategy; + public abstract fun getLength ()I + public abstract fun getMode ()Ldev/kord/voice/EncryptionMode; +} + public final class dev/kord/voice/encryption/strategies/NormalNonceStrategy : dev/kord/voice/encryption/strategies/NonceStrategy { + public static final field Factory Ldev/kord/voice/encryption/strategies/NormalNonceStrategy$Factory; public fun ()V public fun append (Ldev/kord/voice/io/ByteArrayView;Ldev/kord/voice/io/MutableByteArrayCursor;)V public fun generate (Lkotlin/jvm/functions/Function0;)Ldev/kord/voice/io/ByteArrayView; - public fun getNonceLength ()I public fun strip (Ldev/kord/voice/udp/RTPPacket;)Ldev/kord/voice/io/ByteArrayView; } +public final class dev/kord/voice/encryption/strategies/NormalNonceStrategy$Factory : dev/kord/voice/encryption/strategies/NonceStrategy$Factory { + public fun create ()Ldev/kord/voice/encryption/strategies/NonceStrategy; + public fun getLength ()I + public fun getMode ()Ldev/kord/voice/EncryptionMode; +} + public final class dev/kord/voice/encryption/strategies/SuffixNonceStrategy : dev/kord/voice/encryption/strategies/NonceStrategy { + public static final field Factory Ldev/kord/voice/encryption/strategies/SuffixNonceStrategy$Factory; public fun ()V public fun append (Ldev/kord/voice/io/ByteArrayView;Ldev/kord/voice/io/MutableByteArrayCursor;)V public fun generate (Lkotlin/jvm/functions/Function0;)Ldev/kord/voice/io/ByteArrayView; - public fun getNonceLength ()I public fun strip (Ldev/kord/voice/udp/RTPPacket;)Ldev/kord/voice/io/ByteArrayView; } +public final class dev/kord/voice/encryption/strategies/SuffixNonceStrategy$Factory : dev/kord/voice/encryption/strategies/NonceStrategy$Factory { + public fun create ()Ldev/kord/voice/encryption/strategies/NonceStrategy; + public fun getLength ()I + public fun getMode ()Ldev/kord/voice/EncryptionMode; +} + public final class dev/kord/voice/exception/VoiceConnectionInitializationException : java/lang/Exception { public fun (Ljava/lang/String;)V public fun (Ljava/lang/String;Ljava/lang/Throwable;)V @@ -1062,7 +1152,7 @@ public final class dev/kord/voice/io/ReadableByteArrayCursor { } public final class dev/kord/voice/streams/DefaultStreams : dev/kord/voice/streams/Streams { - public fun (Ldev/kord/voice/gateway/VoiceGateway;Ldev/kord/voice/udp/VoiceUdpSocket;Ldev/kord/voice/encryption/strategies/NonceStrategy;)V + public fun (Ldev/kord/voice/gateway/VoiceGateway;Ldev/kord/voice/udp/VoiceUdpSocket;Ldev/kord/voice/encryption/VoiceEncryption;)V public fun getIncomingAudioFrames ()Lkotlinx/coroutines/flow/Flow; public synthetic fun getIncomingAudioPackets ()Lkotlinx/coroutines/flow/Flow; public fun getIncomingAudioPackets ()Lkotlinx/coroutines/flow/SharedFlow; @@ -1111,9 +1201,9 @@ public final class dev/kord/voice/udp/AudioFrameSenderConfiguration { } public abstract class dev/kord/voice/udp/AudioPacketProvider { - public fun ([BLdev/kord/voice/encryption/strategies/NonceStrategy;)V + public fun ([BLdev/kord/voice/encryption/VoiceEncryption;)V + public final fun getEncryption ()Ldev/kord/voice/encryption/VoiceEncryption; public final fun getKey ()[B - public final fun getNonceStrategy ()Ldev/kord/voice/encryption/strategies/NonceStrategy; public abstract fun provide-jfaDVJw (SII[B)Ldev/kord/voice/io/ByteArrayView; } @@ -1124,16 +1214,16 @@ public final class dev/kord/voice/udp/DefaultAudioFrameSender : dev/kord/voice/u } public final class dev/kord/voice/udp/DefaultAudioFrameSenderData { - public fun (Ldev/kord/voice/udp/VoiceUdpSocket;Ldev/kord/voice/FrameInterceptor;Ldev/kord/voice/AudioProvider;Ldev/kord/voice/encryption/strategies/NonceStrategy;)V + public fun (Ldev/kord/voice/udp/VoiceUdpSocket;Ldev/kord/voice/FrameInterceptor;Ldev/kord/voice/AudioProvider;Ldev/kord/voice/encryption/VoiceEncryption;)V public final fun component1 ()Ldev/kord/voice/udp/VoiceUdpSocket; public final fun component2 ()Ldev/kord/voice/FrameInterceptor; public final fun component3 ()Ldev/kord/voice/AudioProvider; - public final fun component4 ()Ldev/kord/voice/encryption/strategies/NonceStrategy; - public final fun copy (Ldev/kord/voice/udp/VoiceUdpSocket;Ldev/kord/voice/FrameInterceptor;Ldev/kord/voice/AudioProvider;Ldev/kord/voice/encryption/strategies/NonceStrategy;)Ldev/kord/voice/udp/DefaultAudioFrameSenderData; - public static synthetic fun copy$default (Ldev/kord/voice/udp/DefaultAudioFrameSenderData;Ldev/kord/voice/udp/VoiceUdpSocket;Ldev/kord/voice/FrameInterceptor;Ldev/kord/voice/AudioProvider;Ldev/kord/voice/encryption/strategies/NonceStrategy;ILjava/lang/Object;)Ldev/kord/voice/udp/DefaultAudioFrameSenderData; + public final fun component4 ()Ldev/kord/voice/encryption/VoiceEncryption; + public final fun copy (Ldev/kord/voice/udp/VoiceUdpSocket;Ldev/kord/voice/FrameInterceptor;Ldev/kord/voice/AudioProvider;Ldev/kord/voice/encryption/VoiceEncryption;)Ldev/kord/voice/udp/DefaultAudioFrameSenderData; + public static synthetic fun copy$default (Ldev/kord/voice/udp/DefaultAudioFrameSenderData;Ldev/kord/voice/udp/VoiceUdpSocket;Ldev/kord/voice/FrameInterceptor;Ldev/kord/voice/AudioProvider;Ldev/kord/voice/encryption/VoiceEncryption;ILjava/lang/Object;)Ldev/kord/voice/udp/DefaultAudioFrameSenderData; public fun equals (Ljava/lang/Object;)Z + public final fun getEncryption ()Ldev/kord/voice/encryption/VoiceEncryption; public final fun getInterceptor ()Ldev/kord/voice/FrameInterceptor; - public final fun getNonceStrategy ()Ldev/kord/voice/encryption/strategies/NonceStrategy; public final fun getProvider ()Ldev/kord/voice/AudioProvider; public final fun getUdp ()Ldev/kord/voice/udp/VoiceUdpSocket; public fun hashCode ()I @@ -1141,7 +1231,7 @@ public final class dev/kord/voice/udp/DefaultAudioFrameSenderData { } public final class dev/kord/voice/udp/DefaultAudioPacketProvider : dev/kord/voice/udp/AudioPacketProvider { - public fun ([BLdev/kord/voice/encryption/strategies/NonceStrategy;)V + public fun ([BLdev/kord/voice/encryption/VoiceEncryption;)V public fun provide-jfaDVJw (SII[B)Ldev/kord/voice/io/ByteArrayView; } diff --git a/voice/build/generated/ksp/main/kotlin/dev/kord/voice/EncryptionMode.kt b/voice/build/generated/ksp/main/kotlin/dev/kord/voice/EncryptionMode.kt index 5f7f80847d5..adb755156f9 100644 --- a/voice/build/generated/ksp/main/kotlin/dev/kord/voice/EncryptionMode.kt +++ b/voice/build/generated/ksp/main/kotlin/dev/kord/voice/EncryptionMode.kt @@ -42,6 +42,10 @@ public sealed class EncryptionMode( `value`: String, ) : EncryptionMode(value) + public object AeadAes256Gcm : EncryptionMode("aead_aes256_gcm") + + public object AeadAes256GcmRtpSize : EncryptionMode("aead_aes256_gcm_rtpsize") + public object XSalsa20Poly1305 : EncryptionMode("xsalsa20_poly1305") public object XSalsa20Poly1305Suffix : EncryptionMode("xsalsa20_poly1305_suffix") @@ -65,6 +69,8 @@ public sealed class EncryptionMode( */ public val entries: List by lazy(mode = PUBLICATION) { listOf( + AeadAes256Gcm, + AeadAes256GcmRtpSize, XSalsa20Poly1305, XSalsa20Poly1305Suffix, XSalsa20Poly1305Lite, @@ -77,6 +83,8 @@ public sealed class EncryptionMode( * specified [value]. */ public fun from(`value`: String): EncryptionMode = when (value) { + "aead_aes256_gcm" -> AeadAes256Gcm + "aead_aes256_gcm_rtpsize" -> AeadAes256GcmRtpSize "xsalsa20_poly1305" -> XSalsa20Poly1305 "xsalsa20_poly1305_suffix" -> XSalsa20Poly1305Suffix "xsalsa20_poly1305_lite" -> XSalsa20Poly1305Lite diff --git a/voice/src/main/kotlin/EncryptionMode.kt b/voice/src/main/kotlin/EncryptionMode.kt index d634833c4f7..6fb0431eb4a 100644 --- a/voice/src/main/kotlin/EncryptionMode.kt +++ b/voice/src/main/kotlin/EncryptionMode.kt @@ -2,9 +2,11 @@ STRING_KORD_ENUM, name = "EncryptionMode", docUrl = "https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-udp-connection-encryption-modes", entries = [ + Entry("AeadAes256Gcm", stringValue = "aead_aes256_gcm"), + Entry("AeadAes256GcmRtpSize", stringValue = "aead_aes256_gcm_rtpsize"), Entry("XSalsa20Poly1305", stringValue = "xsalsa20_poly1305"), Entry("XSalsa20Poly1305Suffix", stringValue = "xsalsa20_poly1305_suffix"), - Entry("XSalsa20Poly1305Lite", stringValue = "xsalsa20_poly1305_lite") + Entry("XSalsa20Poly1305Lite", stringValue = "xsalsa20_poly1305_lite"), ] ) diff --git a/voice/src/main/kotlin/VoiceConnection.kt b/voice/src/main/kotlin/VoiceConnection.kt index c034484c90b..6aae3a6662f 100644 --- a/voice/src/main/kotlin/VoiceConnection.kt +++ b/voice/src/main/kotlin/VoiceConnection.kt @@ -4,7 +4,7 @@ import dev.kord.common.annotation.KordVoice import dev.kord.common.entity.Snowflake import dev.kord.gateway.Gateway import dev.kord.gateway.UpdateVoiceStatus -import dev.kord.voice.encryption.strategies.NonceStrategy +import dev.kord.voice.encryption.VoiceEncryption import dev.kord.voice.gateway.VoiceGateway import dev.kord.voice.gateway.VoiceGatewayConfiguration import dev.kord.voice.handlers.StreamsHandler @@ -41,7 +41,6 @@ public data class VoiceConnectionData( * @param audioProvider a [AudioProvider] that will provide [AudioFrame] when required. * @param frameInterceptor a [FrameInterceptor] that will intercept all outgoing [AudioFrame]s. * @param frameSender the [AudioFrameSender] that will handle the sending of audio packets. - * @param nonceStrategy the [NonceStrategy] that is used during encryption of audio. */ @KordVoice public class VoiceConnection( @@ -54,8 +53,8 @@ public class VoiceConnection( public val audioProvider: AudioProvider, public val frameInterceptor: FrameInterceptor, public val frameSender: AudioFrameSender, - public val nonceStrategy: NonceStrategy, - connectionDetachDuration: Duration + public val encryption: VoiceEncryption, + connectionDetachDuration: Duration, ) { public val scope: CoroutineScope = CoroutineScope(SupervisorJob() + CoroutineName("kord-voice-connection[${data.guildId.value}]")) @@ -148,7 +147,7 @@ public suspend inline fun VoiceConnection( selfId: Snowflake, channelId: Snowflake, guildId: Snowflake, - builder: VoiceConnectionBuilder.() -> Unit = {} + builder: VoiceConnectionBuilder.() -> Unit = {}, ): VoiceConnection { contract { callsInPlace(builder, InvocationKind.EXACTLY_ONCE) } return VoiceConnectionBuilder(gateway, selfId, channelId, guildId).apply(builder).build() diff --git a/voice/src/main/kotlin/VoiceConnectionBuilder.kt b/voice/src/main/kotlin/VoiceConnectionBuilder.kt index 62765a73701..fb0718ad3fa 100644 --- a/voice/src/main/kotlin/VoiceConnectionBuilder.kt +++ b/voice/src/main/kotlin/VoiceConnectionBuilder.kt @@ -7,8 +7,8 @@ import dev.kord.gateway.Gateway import dev.kord.gateway.UpdateVoiceStatus import dev.kord.gateway.VoiceServerUpdate import dev.kord.gateway.VoiceStateUpdate -import dev.kord.voice.encryption.strategies.LiteNonceStrategy -import dev.kord.voice.encryption.strategies.NonceStrategy +import dev.kord.voice.encryption.AeadAes256Gcm +import dev.kord.voice.encryption.VoiceEncryption import dev.kord.voice.exception.VoiceConnectionInitializationException import dev.kord.voice.gateway.DefaultVoiceGatewayBuilder import dev.kord.voice.gateway.VoiceGateway @@ -31,7 +31,7 @@ public class VoiceConnectionBuilder( public var gateway: Gateway, public var selfId: Snowflake, public var channelId: Snowflake, - public var guildId: Snowflake + public var guildId: Snowflake, ) { /** * The amount in milliseconds to wait for the events required to create a [VoiceConnection]. Default is 5000, or 5 seconds. @@ -65,9 +65,10 @@ public class VoiceConnectionBuilder( /** * The nonce strategy to be used for the encryption of audio packets. - * If `null`, [dev.kord.voice.encryption.strategies.LiteNonceStrategy] will be used. + * If `null` & voice receive if disabled, [dev.kord.voice.encryption.AeadAes256Gcm] will be used, + * otherwise [dev.kord.voice.encryption.XSalsa20Poly1305] with the Lite strategy will be used. */ - public var nonceStrategy: NonceStrategy? = null + public var encryption: VoiceEncryption? = null /** * A boolean indicating whether your voice state will be muted. @@ -111,49 +112,50 @@ public class VoiceConnectionBuilder( this.voiceGatewayBuilder = builder } - private suspend fun Gateway.updateVoiceState(): Pair = coroutineScope { - val voiceStateDeferred = async { - withTimeoutOrNull(timeout) { - gateway.events.filterIsInstance() - .filter { it.voiceState.guildId.value == guildId && it.voiceState.userId == selfId } - .first() - .voiceState + private suspend fun Gateway.updateVoiceState(): Pair = + coroutineScope { + val voiceStateDeferred = async { + withTimeoutOrNull(timeout) { + gateway.events.filterIsInstance() + .filter { it.voiceState.guildId.value == guildId && it.voiceState.userId == selfId } + .first() + .voiceState + } } - } - val voiceServerDeferred = async { - withTimeoutOrNull(timeout) { - gateway.events.filterIsInstance() - .filter { it.voiceServerUpdateData.guildId == guildId } - .first() - .voiceServerUpdateData + val voiceServerDeferred = async { + withTimeoutOrNull(timeout) { + gateway.events.filterIsInstance() + .filter { it.voiceServerUpdateData.guildId == guildId } + .first() + .voiceServerUpdateData + } } - } - send( - UpdateVoiceStatus( - guildId = guildId, - channelId = channelId, - selfMute = selfMute, - selfDeaf = selfDeaf, + send( + UpdateVoiceStatus( + guildId = guildId, + channelId = channelId, + selfMute = selfMute, + selfDeaf = selfDeaf, + ) ) - ) - val voiceServer = voiceServerDeferred.await() - val voiceState = voiceStateDeferred.await() + val voiceServer = voiceServerDeferred.await() + val voiceState = voiceStateDeferred.await() - if (voiceServer == null || voiceState == null) - throw VoiceConnectionInitializationException("Did not receive a VoiceStateUpdate and or a VoiceServerUpdate in time!") + if (voiceServer == null || voiceState == null) + throw VoiceConnectionInitializationException("Did not receive a VoiceStateUpdate and or a VoiceServerUpdate in time!") - VoiceConnectionData( - selfId, - guildId, - voiceState.sessionId - ) to VoiceGatewayConfiguration( - voiceServer.token, - "wss://${voiceServer.endpoint}/?v=${KordConfiguration.VOICE_GATEWAY_VERSION}", - ) - } + VoiceConnectionData( + selfId, + guildId, + voiceState.sessionId + ) to VoiceGatewayConfiguration( + voiceServer.token, + "wss://${voiceServer.endpoint}/?v=${KordConfiguration.VOICE_GATEWAY_VERSION}", + ) + } /** * @throws dev.kord.voice.exception.VoiceConnectionInitializationException when there was a problem retrieving voice information from Discord. @@ -166,7 +168,7 @@ public class VoiceConnectionBuilder( .build() val udpSocket = udpSocket ?: GlobalVoiceUdpSocket val audioProvider = audioProvider ?: EmptyAudioPlayerProvider - val nonceStrategy = nonceStrategy ?: LiteNonceStrategy() + val encryption = encryption ?: AeadAes256Gcm val frameInterceptor = frameInterceptor ?: DefaultFrameInterceptor() val audioSender = audioSender ?: DefaultAudioFrameSender( @@ -174,11 +176,11 @@ public class VoiceConnectionBuilder( udpSocket, frameInterceptor, audioProvider, - nonceStrategy + encryption ) ) val streams = - streams ?: if (receiveVoice) DefaultStreams(voiceGateway, udpSocket, nonceStrategy) else NOPStreams + streams ?: if (receiveVoice) DefaultStreams(voiceGateway, udpSocket, encryption) else NOPStreams return VoiceConnection( voiceConnectionData, @@ -190,7 +192,7 @@ public class VoiceConnectionBuilder( audioProvider, frameInterceptor, audioSender, - nonceStrategy, + encryption, connectionDetachDuration ) } diff --git a/voice/src/main/kotlin/encryption/AeadAes256Gcm.kt b/voice/src/main/kotlin/encryption/AeadAes256Gcm.kt new file mode 100644 index 00000000000..fa08d955480 --- /dev/null +++ b/voice/src/main/kotlin/encryption/AeadAes256Gcm.kt @@ -0,0 +1,107 @@ +package dev.kord.voice.encryption + +import dev.kord.voice.EncryptionMode +import dev.kord.voice.encryption.VoiceEncryption.Box +import dev.kord.voice.encryption.VoiceEncryption.Unbox +import dev.kord.voice.io.ByteArrayView +import dev.kord.voice.io.MutableByteArrayCursor +import dev.kord.voice.io.mutableCursor +import dev.kord.voice.io.view +import dev.kord.voice.udp.RTPPacket +import javax.crypto.Cipher +import javax.crypto.spec.GCMParameterSpec +import javax.crypto.spec.SecretKeySpec + +/** + * An [encryption method][VoiceEncryption] that uses the AES-256 GCM cipher. + */ +public data object AeadAes256Gcm : VoiceEncryption { + private const val AUTH_TAG_LEN = 16 + private const val NONCE_LEN = 4 + private const val IV_LEN = 12 + + override val mode: EncryptionMode get() = EncryptionMode.AeadAes256Gcm + + override val nonceLength: Int get() = 4 + + override fun createBox(key: ByteArray): Box = BoxImpl(key) + + override fun createUnbox(key: ByteArray): Unbox = UnboxImpl(key) + + private abstract class Common(key: ByteArray) { + protected val iv = ByteArray(IV_LEN) + protected val ivCursor = iv.mutableCursor() + + protected val cipherKey = SecretKeySpec(key, "AES") + protected val cipher: Cipher = Cipher.getInstance("AES/GCM/NoPadding") + + fun apply( + mode: Int, + src: ByteArrayView, + dst: MutableByteArrayCursor, + aead: ByteArrayView, + nonce: ByteArray, + writeNonce: MutableByteArrayCursor.(nonce: ByteArray) -> Unit, + ): Boolean { + iv.fill(0) + ivCursor.reset() + ivCursor.apply { writeNonce(nonce) } + + init(mode) + cipher.updateAAD(aead.data, aead.dataStart, aead.viewSize) + dst.cursor += cipher.doFinal(src.data, src.dataStart, src.viewSize, dst.data, dst.cursor) + + return true + } + + fun init(mode: Int) { + cipher.init(mode, cipherKey, GCMParameterSpec(AUTH_TAG_LEN * 8, iv, 0, IV_LEN)) + } + } + + private class BoxImpl(key: ByteArray) : Box, Common(key) { + val nonceBuffer: ByteArray = ByteArray(NONCE_LEN) + val nonceCursor by lazy { nonceBuffer.mutableCursor() } + val nonceView by lazy { nonceBuffer.view() } + + override val overhead: Int + get() = AUTH_TAG_LEN + NONCE_LEN + + override fun apply( + src: ByteArrayView, + dst: MutableByteArrayCursor, + aead: ByteArrayView, + nonce: ByteArray, + ): Boolean = apply(Cipher.ENCRYPT_MODE, src, dst, aead, nonce, MutableByteArrayCursor::writeByteArray) + + override fun appendNonce(nonce: ByteArrayView, dst: MutableByteArrayCursor) { + dst.writeByteView(nonce) + } + + override fun generateNonce(header: () -> ByteArrayView): ByteArrayView { + nonceCursor.reset() + nonceCursor.writeByteView(header().view(0, NONCE_LEN)!!) + return nonceView + } + } + + private class UnboxImpl(key: ByteArray) : Unbox, Common(key) { + override fun apply( + src: ByteArrayView, + dst: MutableByteArrayCursor, + aead: ByteArrayView, + nonce: ByteArray, + ): Boolean = apply(Cipher.DECRYPT_MODE, src, dst, aead, nonce) { writeByteView(it.view(0, NONCE_LEN)!!) } + + override fun getNonce(packet: RTPPacket): ByteArrayView = with(packet.payload) { + // grab the last NONCE_LEN bytes of the packet payload. + val nonce = view(dataEnd - NONCE_LEN, dataEnd) + ?: error("Failed to strip nonce from RTP packet payload.") + + // resize the payload view to exclude the nonce. + resize(0, dataEnd - NONCE_LEN) + + return nonce + } + } +} \ No newline at end of file diff --git a/voice/src/main/kotlin/encryption/VoiceEncryption.kt b/voice/src/main/kotlin/encryption/VoiceEncryption.kt new file mode 100644 index 00000000000..9e3bf449283 --- /dev/null +++ b/voice/src/main/kotlin/encryption/VoiceEncryption.kt @@ -0,0 +1,68 @@ +package dev.kord.voice.encryption + +import dev.kord.voice.EncryptionMode +import dev.kord.voice.io.ByteArrayView +import dev.kord.voice.io.MutableByteArrayCursor +import dev.kord.voice.udp.RTPPacket + +// TODO: improve kdoc +// TODO: improve nonce methods to reduce unnecessary byte copying. +// TODO: commonize nonce methods. + +public interface VoiceEncryption { + public val nonceLength: Int + + /** + * The [EncryptionMode] this encryption strategy fulfills. + */ + public val mode: EncryptionMode + + /** + * Creates a [Box] instance for the specified [key bytes][key] + * + * @param key A byte array containing the 256-bit key material. + */ + public fun createBox(key: ByteArray): Box + + /** + * Creates a [Box] instance for the specified [key bytes][key] + * + * @param key A byte array containing the 256-bit key material. + */ + public fun createUnbox(key: ByteArray): Unbox + + /** + * A common interface for (un)boxing voice packets. + */ + public sealed interface Method { + + public fun apply(src: ByteArrayView, dst: MutableByteArrayCursor, aead: ByteArrayView, nonce: ByteArray): Boolean + } + + public interface Box : Method { + /** + * The number of extra bytes this [Box] generates. + */ + public val overhead: Int + + /** + * + */ + public fun generateNonce(header: () -> ByteArrayView): ByteArrayView + + /** + * Appends the specified [nonce buffer][nonce] to the [destination cursor][dst] + */ + public fun appendNonce(nonce: ByteArrayView, dst: MutableByteArrayCursor) + } + + public interface Unbox : Method { + + /** + * Returns the nonce from the given [RTP packet][packet]. + * + * @return the nonce. + */ + public fun getNonce(packet: RTPPacket): ByteArrayView + } +} diff --git a/voice/src/main/kotlin/encryption/XSalsa20Poly1305.kt b/voice/src/main/kotlin/encryption/XSalsa20Poly1305.kt new file mode 100644 index 00000000000..ee5e9774650 --- /dev/null +++ b/voice/src/main/kotlin/encryption/XSalsa20Poly1305.kt @@ -0,0 +1,95 @@ +package dev.kord.voice.encryption + +import com.iwebpp.crypto.TweetNaclFast +import com.iwebpp.crypto.TweetNaclFast.SecretBox.boxzerobytesLength +import com.iwebpp.crypto.TweetNaclFast.SecretBox.zerobytesLength +import dev.kord.voice.EncryptionMode +import dev.kord.voice.encryption.strategies.LiteNonceStrategy +import dev.kord.voice.encryption.strategies.NonceStrategy +import dev.kord.voice.io.ByteArrayView +import dev.kord.voice.io.MutableByteArrayCursor +import dev.kord.voice.udp.RTPPacket + +/** + * An [encryption method][VoiceEncryption] that uses the XSalsa20 stream cipher and Poly1035 hash function. + */ +public data class XSalsa20Poly1305(public val nonceStrategyFactory: NonceStrategy.Factory = LiteNonceStrategy) : VoiceEncryption { + override val mode: EncryptionMode get() = nonceStrategyFactory.mode + + override val nonceLength: Int get() = 24 + + override fun createBox(key: ByteArray): VoiceEncryption.Box = Impl.Box(key, nonceStrategyFactory) + + override fun createUnbox(key: ByteArray): VoiceEncryption.Unbox = Impl.Unbox(key, nonceStrategyFactory) + + public sealed class Impl(protected val nonceStrategyFactory: NonceStrategy.Factory) { + protected val nonceStrategy: NonceStrategy = nonceStrategyFactory.create() + + // this class is only used internally and is used for encrypting opus packets. + // we can know the maximum sized buffer required to store any opus packet. + protected val m: ByteArray = ByteArray(OPUS_MAX_LENGTH + zerobytesLength) + protected val c: ByteArray = ByteArray(OPUS_MAX_LENGTH + zerobytesLength) + + public class Box( + private val key: ByteArray, + nonceStrategyFactory: NonceStrategy.Factory, + ) : VoiceEncryption.Box, Impl(nonceStrategyFactory) { + override val overhead: Int + get() = boxzerobytesLength + nonceStrategyFactory.length + + override fun apply(src: ByteArrayView, dst: MutableByteArrayCursor, aead: ByteArrayView, nonce: ByteArray): Boolean { + m.fill(0) + c.fill(0) + + for (i in 0.. ByteArrayView): ByteArrayView = + nonceStrategy.generate(header) + + override fun appendNonce(nonce: ByteArrayView, dst: MutableByteArrayCursor): Unit = + nonceStrategy.append(nonce, dst) + } + + public class Unbox( + private val key: ByteArray, + nonceStrategyFactory: NonceStrategy.Factory, + ) : VoiceEncryption.Unbox, Impl(nonceStrategyFactory) { + override fun apply(src: ByteArrayView, dst: MutableByteArrayCursor, aead: ByteArrayView, nonce: ByteArray): Boolean { + c.fill(0) + m.fill(0) + + for (i in 0.., - private val connection: VoiceConnection + private val connection: VoiceConnection, ) : ConnectionEventHandler(flow, "UdpInterceptor") { private var ssrc: UInt? by atomic(null) private var server: InetSocketAddress? by atomic(null) @@ -37,18 +33,12 @@ internal class UdpLifeCycleHandler( udpLifeCycleLogger.trace { "ip discovered for voice successfully" } - val encryptionMode = when (connection.nonceStrategy) { - is LiteNonceStrategy -> EncryptionMode.XSalsa20Poly1305Lite - is NormalNonceStrategy -> EncryptionMode.XSalsa20Poly1305 - is SuffixNonceStrategy -> EncryptionMode.XSalsa20Poly1305Suffix - } - val selectProtocol = SelectProtocol( protocol = "udp", data = SelectProtocol.Data( address = ip.hostname, port = ip.port, - mode = encryptionMode + mode = connection.encryption.mode ) ) diff --git a/voice/src/main/kotlin/streams/DefaultStreams.kt b/voice/src/main/kotlin/streams/DefaultStreams.kt index 0907f1ff895..5a8956f2d9a 100644 --- a/voice/src/main/kotlin/streams/DefaultStreams.kt +++ b/voice/src/main/kotlin/streams/DefaultStreams.kt @@ -1,11 +1,9 @@ package dev.kord.voice.streams -import com.iwebpp.crypto.TweetNaclFast import dev.kord.common.annotation.KordVoice import dev.kord.common.entity.Snowflake import dev.kord.voice.AudioFrame -import dev.kord.voice.encryption.XSalsa20Poly1305Codec -import dev.kord.voice.encryption.strategies.NonceStrategy +import dev.kord.voice.encryption.VoiceEncryption import dev.kord.voice.gateway.Speaking import dev.kord.voice.gateway.VoiceGateway import dev.kord.voice.io.* @@ -28,14 +26,14 @@ private val defaultStreamsLogger = KotlinLogging.logger { } public class DefaultStreams( private val voiceGateway: VoiceGateway, private val udp: VoiceUdpSocket, - private val nonceStrategy: NonceStrategy + private val encryption: VoiceEncryption, ) : Streams { private fun CoroutineScope.listenForIncoming(key: ByteArray, server: SocketAddress) { udp.incoming .filter { it.address == server } .mapNotNull { RTPPacket.fromPacket(it.packet) } .filter { it.payloadType == PayloadType.Audio.raw } - .decrypt(nonceStrategy, key) + .decrypt(encryption, key) .clean() .onEach { _incomingAudioPackets.emit(it) } .launchIn(this) @@ -86,36 +84,41 @@ public class DefaultStreams( override val ssrcToUser: Map get() = _ssrcToUser.value } -private fun Flow.decrypt(nonceStrategy: NonceStrategy, key: ByteArray): Flow { - val codec = XSalsa20Poly1305Codec(key) - val nonceBuffer = ByteArray(TweetNaclFast.SecretBox.nonceLength).mutableCursor() +private fun Flow.decrypt(encryption: VoiceEncryption, key: ByteArray): Flow { + val unbox = encryption.createUnbox(key) + val nonceBuffer = ByteArray(encryption.nonceLength).mutableCursor() + + val aeadBuffer = ByteArray(12) + val aeadCursor = aeadBuffer.mutableCursor() + val aeadView = aeadBuffer.view() val decryptedBuffer = ByteArray(512) val decryptedCursor = decryptedBuffer.mutableCursor() val decryptedView = decryptedBuffer.view() - return mapNotNull { + return mapNotNull { packet -> + // strip and write the nonce. nonceBuffer.reset() - decryptedCursor.reset() - - nonceBuffer.writeByteView(nonceStrategy.strip(it)) + nonceBuffer.writeByteView(unbox.getNonce(packet)) - val decrypted = with(it.payload) { - codec.decrypt(data, dataStart, viewSize, nonceBuffer.data, decryptedCursor) - } + // write the RTP packet header to the AEAD buffer. + aeadCursor.reset() + packet.writeHeader(aeadCursor) - if (!decrypted) { - defaultStreamsLogger.trace { "failed to decrypt the packet with data ${it.payload.data.contentToString()} at offset ${it.payload.dataStart} and length ${it.payload.viewSize - 4}" } + // decrypt the RTP packet payload. + decryptedCursor.reset() + if (!unbox.apply(packet.payload, decryptedCursor, aeadView, nonceBuffer.data)) { + defaultStreamsLogger.trace { "failed to decrypt the packet with data ${packet.payload.data.contentToString()} at offset ${packet.payload.dataStart} and length ${packet.payload.viewSize - 4}" } return@mapNotNull null } decryptedView.resize(0, decryptedCursor.cursor) // mutate the payload data and update the view - it.payload.data.mutableCursor().writeByteViewOrResize(decryptedView) - it.payload.resize(0, decryptedView.viewSize) + packet.payload.data.mutableCursor().writeByteViewOrResize(decryptedView) + packet.payload.resize(0, decryptedView.viewSize) - it + packet } } diff --git a/voice/src/main/kotlin/udp/AudioPacketProvider.kt b/voice/src/main/kotlin/udp/AudioPacketProvider.kt index 05f2e522d4c..5f23de7641e 100644 --- a/voice/src/main/kotlin/udp/AudioPacketProvider.kt +++ b/voice/src/main/kotlin/udp/AudioPacketProvider.kt @@ -1,23 +1,23 @@ package dev.kord.voice.udp -import com.iwebpp.crypto.TweetNaclFast -import dev.kord.voice.encryption.XSalsa20Poly1305Codec -import dev.kord.voice.encryption.strategies.NonceStrategy +import dev.kord.voice.encryption.VoiceEncryption import dev.kord.voice.io.ByteArrayView import dev.kord.voice.io.MutableByteArrayCursor import dev.kord.voice.io.mutableCursor import dev.kord.voice.io.view -public abstract class AudioPacketProvider(public val key: ByteArray, public val nonceStrategy: NonceStrategy) { +public abstract class AudioPacketProvider(public val key: ByteArray, public val encryption: VoiceEncryption) { public abstract fun provide(sequence: UShort, timestamp: UInt, ssrc: UInt, data: ByteArray): ByteArrayView } private class CouldNotEncryptDataException(data: ByteArray) : RuntimeException("Couldn't encrypt the following data: [${data.joinToString(", ")}]") -public class DefaultAudioPacketProvider(key: ByteArray, nonceStrategy: NonceStrategy) : - AudioPacketProvider(key, nonceStrategy) { - private val codec = XSalsa20Poly1305Codec(key) +public class DefaultAudioPacketProvider(key: ByteArray, encryption: VoiceEncryption) : AudioPacketProvider( + key, + encryption +) { + private val box = encryption.createBox(key) private val packetBuffer = ByteArray(2048) private val packetBufferCursor: MutableByteArrayCursor = packetBuffer.mutableCursor() @@ -25,7 +25,7 @@ public class DefaultAudioPacketProvider(key: ByteArray, nonceStrategy: NonceStra private val rtpHeaderView: ByteArrayView = packetBuffer.view(0, RTP_HEADER_LENGTH)!! - private val nonceBuffer: MutableByteArrayCursor = ByteArray(TweetNaclFast.SecretBox.nonceLength).mutableCursor() + private val nonceBuffer: MutableByteArrayCursor = ByteArray(encryption.nonceLength).mutableCursor() private val lock: Any = Any() @@ -44,20 +44,19 @@ public class DefaultAudioPacketProvider(key: ByteArray, nonceStrategy: NonceStra nonceBuffer.reset() // make sure we enough room in this buffer - resize(RTP_HEADER_LENGTH + (data.size + TweetNaclFast.SecretBox.boxzerobytesLength) + nonceStrategy.nonceLength) + resize(RTP_HEADER_LENGTH + data.size + box.overhead) // write header and generate nonce writeHeader(sequence.toShort(), timestamp.toInt(), ssrc.toInt()) - val rawNonce = nonceStrategy.generate { rtpHeaderView } + val rawNonce = box.generateNonce { rtpHeaderView } nonceBuffer.writeByteView(rawNonce) // encrypt data and write into our buffer - val encrypted = codec.encrypt(data, nonce = nonceBuffer.data, output = this) - + val encrypted = box.apply(data.view(), this, rtpHeaderView, nonceBuffer.data) if (!encrypted) throw CouldNotEncryptDataException(data) - nonceStrategy.append(rawNonce, this) + box.appendNonce(rawNonce, this) // let's make sure we have the correct view of the packet if (!packetBufferView.resize(0, cursor)) error("couldn't resize packet buffer view?!") diff --git a/voice/src/main/kotlin/udp/DefaultAudioFrameSender.kt b/voice/src/main/kotlin/udp/DefaultAudioFrameSender.kt index 3edeb832c77..8a59cce29f9 100644 --- a/voice/src/main/kotlin/udp/DefaultAudioFrameSender.kt +++ b/voice/src/main/kotlin/udp/DefaultAudioFrameSender.kt @@ -4,7 +4,7 @@ import dev.kord.common.annotation.KordVoice import dev.kord.voice.AudioFrame import dev.kord.voice.AudioProvider import dev.kord.voice.FrameInterceptor -import dev.kord.voice.encryption.strategies.NonceStrategy +import dev.kord.voice.encryption.VoiceEncryption import io.github.oshai.kotlinlogging.KotlinLogging import io.ktor.network.sockets.* import io.ktor.utils.io.core.* @@ -21,7 +21,7 @@ public data class DefaultAudioFrameSenderData( val udp: VoiceUdpSocket, val interceptor: FrameInterceptor, val provider: AudioProvider, - val nonceStrategy: NonceStrategy, + val encryption: VoiceEncryption, ) @KordVoice @@ -31,7 +31,7 @@ public class DefaultAudioFrameSender( override suspend fun start(configuration: AudioFrameSenderConfiguration): Unit = coroutineScope { var sequence: UShort = Random.nextBits(UShort.SIZE_BITS).toUShort() - val packetProvider = DefaultAudioPacketProvider(configuration.key, data.nonceStrategy) + val packetProvider = DefaultAudioPacketProvider(configuration.key, data.encryption) val frames = Channel(Channel.RENDEZVOUS) with(data.provider) { launch { provideFrames(frames) } }