2828#include < arpa/inet.h>
2929#include < netinet/in.h>
3030
31+ #include < srtp2/srtp.h>
32+
3133// #define LOG_NDEBUG 0
3234#define LOG_TAG " AudioGroup"
3335#include < cutils/atomic.h>
@@ -100,6 +102,9 @@ class AudioStream
100102 AudioCodec *codec, int sampleRate, int sampleCount,
101103 int codecType, int dtmfType);
102104
105+ const char *setCipher (const char *cipher, unsigned char *inkey,
106+ unsigned char *outkey);
107+
103108 void sendDtmf (int event);
104109 bool mix (int32_t *output, int head, int tail, int sampleRate);
105110 void encode (int tick, AudioStream *chain);
@@ -143,6 +148,9 @@ class AudioStream
143148
144149 AudioStream *mNext ;
145150
151+ srtp_ctx_t *srtpIn;
152+ srtp_ctx_t *srtpOut;
153+
146154 friend class AudioGroup ;
147155};
148156
@@ -152,16 +160,70 @@ AudioStream::AudioStream()
152160 mCodec = NULL ;
153161 mBuffer = NULL ;
154162 mNext = NULL ;
163+ srtpIn = NULL ;
164+ srtpOut = NULL ;
155165}
156166
157167AudioStream::~AudioStream ()
158168{
159169 close (mSocket );
160170 delete mCodec ;
161171 delete [] mBuffer ;
172+ if (srtpIn || srtpOut) {
173+ srtp_dealloc (srtpIn);
174+ srtp_dealloc (srtpOut);
175+ }
162176 ALOGD (" stream[%d] is dead" , mSocket );
163177}
164178
179+ const char *AudioStream::setCipher (const char *cipher, unsigned char *inkey,
180+ unsigned char *outkey)
181+ {
182+ srtp_policy_t policy;
183+
184+ memset (&policy, 0 , sizeof (policy));
185+
186+ /*
187+ * Cipher list here must match strings in Crypto.java
188+ */
189+ if (strcmp (cipher, " AES_CM_128_HMAC_SHA1_32" ) == 0 ) {
190+ srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32 (&policy.rtp );
191+ } else if (strcmp (cipher, " AES_CM_128_HMAC_SHA1_80" ) == 0 ) {
192+ srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80 (&policy.rtp );
193+ } else if (strcmp (cipher, " AEAD_AES_128_GCM" ) == 0 ) {
194+ srtp_crypto_policy_set_aes_gcm_128_16_auth (&policy.rtp );
195+ } else if (strcmp (cipher, " AEAD_AES_128_GCM_8" ) == 0 ) {
196+ srtp_crypto_policy_set_aes_gcm_128_8_auth (&policy.rtp );
197+ } else {
198+ ALOGE (" stream[%d] unrecognized cipher %s" , mSocket , cipher);
199+ return " Unrecognized cipher" ;
200+ }
201+
202+ // use the policy twice (it gets copied not pointed to)
203+ policy.ssrc .type = ssrc_any_inbound;
204+ policy.ssrc .value = 0 ;
205+ policy.key = inkey;
206+ policy.allow_repeat_tx = 1 ;
207+ auto ret = srtp_create (&srtpIn, &policy);
208+ if (ret != srtp_err_status_ok) {
209+ ALOGE (" stream[%d] failed to allocate ctx for cipher %s" , mSocket ,
210+ cipher);
211+ return " Failed to allocate srtp ctx for inkey" ;
212+ }
213+ policy.ssrc .type = ssrc_any_outbound;
214+ policy.ssrc .value = 0 ;
215+ policy.key = outkey;
216+ policy.allow_repeat_tx = 1 ;
217+ ret = srtp_create (&srtpOut, &policy);
218+ if (ret != srtp_err_status_ok) {
219+ ALOGE (" stream[%d] failed to allocate ctx for cipher %s" , mSocket ,
220+ cipher);
221+ return " Failed to allocate srtp ctx for outkey" ;
222+ }
223+ ALOGD (" stream[%d] set cipher %s" , mSocket , cipher);
224+ return NULL ;
225+ }
226+
165227bool AudioStream::set (int mode, int socket, sockaddr_storage *remote,
166228 AudioCodec *codec, int sampleRate, int sampleCount,
167229 int codecType, int dtmfType)
@@ -283,7 +345,8 @@ void AudioStream::encode(int tick, AudioStream *chain)
283345 // Make sure duration is reasonable.
284346 if (duration >= 0 && duration < mSampleRate * DTMF_PERIOD ) {
285347 duration += mSampleCount ;
286- int32_t buffer[4 ] = {
348+ // 5 words of slop for encryption
349+ int32_t buffer[9 ] = {
287350 static_cast <int32_t >(htonl (mDtmfMagic | mSequence )),
288351 static_cast <int32_t >(htonl (mDtmfStart )),
289352 static_cast <int32_t >(mSsrc ),
@@ -293,14 +356,27 @@ void AudioStream::encode(int tick, AudioStream *chain)
293356 buffer[3 ] |= htonl (1 << 23 );
294357 mDtmfEvent = -1 ;
295358 }
296- sendto (mSocket , buffer, sizeof (buffer), MSG_DONTWAIT ,
297- (sockaddr *)&mRemote , sizeof (mRemote ));
359+ int length = 16 ; // size of the unencrypted buffer
360+ if (srtpOut) {
361+ int len = length;
362+ auto ret = srtp_protect (srtpOut, buffer, &len);
363+ if (ret != srtp_err_status_ok) {
364+ ALOGE (" stream[%d] failed on encrypt %d" , mSocket , ret);
365+ return ;
366+ }
367+ length = len;
368+ }
369+ sendto (mSocket , buffer, length, MSG_DONTWAIT ,
370+ (sockaddr *)&mRemote , sizeof (mRemote ));
298371 return ;
299372 }
300373 mDtmfEvent = -1 ;
301374 }
302-
303- int32_t buffer[mSampleCount + 3 ];
375+ /*
376+ * For encrypted SRTP we need slop in the buffer for the authentication
377+ * tag and padding, so reserve 5 words
378+ */
379+ int32_t buffer[mSampleCount + 3 + (srtpOut ? 5 : 0 )];
304380 bool data = false ;
305381 if (mMode != RECEIVE_ONLY ) {
306382 // Mix all other streams.
@@ -353,6 +429,15 @@ void AudioStream::encode(int tick, AudioStream *chain)
353429 ALOGV (" stream[%d] encoder error" , mSocket );
354430 return ;
355431 }
432+ if (srtpOut) {
433+ int len = length + 12 ;
434+ auto ret = srtp_protect (srtpOut, buffer, &len);
435+ if (ret != srtp_err_status_ok) {
436+ ALOGE (" stream[%d] failed on encrypt %d" , mSocket , ret);
437+ return ;
438+ }
439+ length = len - 12 ;
440+ }
356441 sendto (mSocket , buffer, length + 12 , MSG_DONTWAIT , (sockaddr *)&mRemote ,
357442 sizeof (mRemote ));
358443}
@@ -386,15 +471,15 @@ void AudioStream::decode(int tick)
386471 mLatencyScore = score;
387472 mLatencyTimer = tick;
388473 } else if (tick - mLatencyTimer >= MEASURE_PERIOD ) {
389- ALOGV (" stream[%d] reduces latency of %dms" , mSocket , mLatencyScore );
474+ ALOGD (" stream[%d] reduces latency of %dms" , mSocket , mLatencyScore );
390475 mBufferTail -= mLatencyScore ;
391476 mLatencyScore = -1 ;
392477 }
393478
394479 int count = (BUFFER_SIZE - (mBufferTail - mBufferHead )) * mSampleRate ;
395480 if (count < mSampleCount ) {
396481 // Buffer overflow. Drop the packet.
397- ALOGV (" stream[%d] buffer overflow" , mSocket );
482+ ALOGD (" stream[%d] buffer overflow" , mSocket );
398483 recv (mSocket , &c, 1 , MSG_DONTWAIT );
399484 return ;
400485 }
@@ -418,21 +503,30 @@ void AudioStream::decode(int tick)
418503 // reliable but at least they can be used to identify duplicates?
419504 if (length < 12 || length > bufferSize ||
420505 (ntohl (*(uint32_t *)buffer) & 0xC07F0000 ) != mCodecMagic ) {
421- ALOGV (" stream[%d] malformed packet" , mSocket );
506+ ALOGD (" stream[%d] malformed packet" , mSocket );
422507 return ;
423508 }
424509 int offset = 12 + ((buffer[0 ] & 0x0F ) << 2 );
425510 if (offset+2 >= bufferSize) {
426- ALOGV (" invalid buffer offset: %d" , offset+2 );
511+ ALOGD (" invalid buffer offset: %d" , offset+2 );
427512 return ;
428513 }
429514 if ((buffer[0 ] & 0x10 ) != 0 ) {
430515 offset += 4 + (ntohs (*(uint16_t *)&buffer[offset + 2 ]) << 2 );
431516 }
432517 if (offset >= bufferSize) {
433- ALOGV (" invalid buffer offset: %d" , offset);
518+ ALOGD (" invalid buffer offset: %d" , offset);
434519 return ;
435520 }
521+ if (srtpIn) {
522+ int len = length;
523+ auto ret = srtp_unprotect (srtpIn, buffer, &len);
524+ if (ret != srtp_err_status_ok) {
525+ ALOGE (" stream[%d] decrypt failed %d" , mSocket , ret);
526+ return ;
527+ }
528+ length = len;
529+ }
436530 if ((buffer[0 ] & 0x20 ) != 0 ) {
437531 length -= buffer[length - 1 ];
438532 }
@@ -953,7 +1047,8 @@ static jfieldID gMode;
9531047
9541048jlong add (JNIEnv *env, jobject thiz, jint mode,
9551049 jint socket, jstring jRemoteAddress, jint remotePort,
956- jstring jCodecSpec, jint dtmfType, jstring opPackageNameStr)
1050+ jstring jCodecSpec, jint dtmfType, jstring opPackageNameStr,
1051+ jstring jCipher, jbyteArray local_key, jbyteArray remote_key)
9571052{
9581053 AudioCodec *codec = NULL ;
9591054 AudioStream *stream = NULL ;
@@ -1005,6 +1100,25 @@ jlong add(JNIEnv *env, jobject thiz, jint mode,
10051100 " cannot initialize audio stream" );
10061101 goto error;
10071102 }
1103+ if (jCipher) {
1104+ const char *cipher = env->GetStringUTFChars (jCipher, NULL );
1105+ if (!cipher) {
1106+ // Exception already thrown.
1107+ return 0 ;
1108+ }
1109+ jbyte *inkey = env->GetByteArrayElements (remote_key, NULL );
1110+ jbyte *outkey = env->GetByteArrayElements (local_key, NULL );
1111+
1112+ const char *ret = stream->setCipher (cipher, (unsigned char *)inkey,
1113+ (unsigned char *)outkey);
1114+ env->ReleaseByteArrayElements (remote_key, inkey, JNI_ABORT );
1115+ env->ReleaseByteArrayElements (local_key, outkey, JNI_ABORT );
1116+ env->ReleaseStringUTFChars (jCipher, cipher);
1117+ if (ret) {
1118+ jniThrowException (env, " java/lang/IllegalStateException" , ret);
1119+ return 0 ;
1120+ }
1121+ }
10081122 socket = -1 ;
10091123 codec = NULL ;
10101124
@@ -1068,7 +1182,7 @@ void sendDtmf(JNIEnv *env, jobject thiz, jint event)
10681182}
10691183
10701184JNINativeMethod gMethods [] = {
1071- {" nativeAdd" , " (IILjava/lang/String;ILjava/lang/String;ILjava/lang/String;)J" , (void *)add},
1185+ {" nativeAdd" , " (IILjava/lang/String;ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;[B[B )J" , (void *)add},
10721186 {" nativeRemove" , " (J)V" , (void *)remove},
10731187 {" nativeSetMode" , " (I)V" , (void *)setMode},
10741188 {" nativeSendDtmf" , " (I)V" , (void *)sendDtmf},
@@ -1092,5 +1206,11 @@ int registerAudioGroup(JNIEnv *env)
10921206 ALOGE (" JNI registration failed" );
10931207 return -1 ;
10941208 }
1209+ auto err = srtp_init ();
1210+ if (err != srtp_err_status_ok) {
1211+ ALOGE (" SRTP initialization failed" );
1212+ return -1 ;
1213+ }
1214+
10951215 return 0 ;
10961216}
0 commit comments