Merge pull request #80 from coien/master

Thank you for the contribution.
diff --git a/Makefile.in b/Makefile.in
index bbbbab7..eb4ce65 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -157,12 +157,14 @@
 
 $(testapp): libsrtp.a
 
-test/rtpw$(EXE): test/rtpw.c test/rtp.c test/getopt_s.c
-	$(COMPILE) $(LDFLAGS) -o $@ $^ $(LIBS) $(SRTPLIB)
+test/rtpw$(EXE): test/rtpw.c test/rtp.c test/getopt_s.c \
+        crypto/math/datatypes.c
+	$(COMPILE) -DTESTAPP_SOURCE=1 $(LDFLAGS) -o $@ $^ $(LIBS) $(SRTPLIB)
 
 ifeq (1, $(HAVE_PCAP))
-test/rtp_decoder$(EXE): test/rtp_decoder.c test/rtp.c test/getopt_s.c
-	$(COMPILE) $(LDFLAGS) -o $@ $^ $(LIBS) $(SRTPLIB)
+test/rtp_decoder$(EXE): test/rtp_decoder.c test/rtp.c test/getopt_s.c \
+        crypto/math/datatypes.c
+	$(COMPILE) -DTESTAPP_SOURCE=1 $(LDFLAGS) -o $@ $^ $(LIBS) $(SRTPLIB)
 endif
 
 test/srtp_driver$(EXE): test/srtp_driver.c test/getopt_s.c
diff --git a/README b/README
index 97f382c..b3ee608 100644
--- a/README
+++ b/README
@@ -78,7 +78,7 @@
   Manual srtp keying uses the -k option; automated key management
   using gdoi will be added later.
 
-usage: rtpw [-d <debug>]* [-k <key> [-a][-e <key size>][-g]] [-s | -r] dest_ip dest_port
+usage: rtpw [-d <debug>]* [-k|b <key> [-a][-e <key size>][-g]] [-s | -r] dest_ip dest_port
 or     rtpw -l
 
   Either the -s (sender) or -r (receiver) option must be chosen.
@@ -96,6 +96,8 @@
 		key is a hexadecimal value (without the
                 leading "0x")
 
+  -b <key>      same as -k but with base64 encoded key
+
   -e <keysize>  encrypt/decrypt (for data confidentiality)
                 (requires use of -k option as well)
                 (use 128, 192, or 256 for keysize)
diff --git a/crypto/include/datatypes.h b/crypto/include/datatypes.h
index a9bdd4c..b18435f 100644
--- a/crypto/include/datatypes.h
+++ b/crypto/include/datatypes.h
@@ -509,4 +509,8 @@
 char *
 bitvector_bit_string(bitvector_t *x, char* buf, int len);
 
+#ifdef TESTAPP_SOURCE
+int base64_string_to_octet_string(char *raw, int *pad, char *base64, int len);
+#endif
+
 #endif /* _DATATYPES_H */
diff --git a/crypto/math/datatypes.c b/crypto/math/datatypes.c
index 1e219fe..c4af8d7 100644
--- a/crypto/math/datatypes.c
+++ b/crypto/math/datatypes.c
@@ -529,196 +529,41 @@
   
 }
 
+#ifdef TESTAPP_SOURCE
 
-/*
- *  From RFC 1521: The Base64 Alphabet
- *
- *   Value Encoding  Value Encoding  Value Encoding  Value Encoding
- *        0 A            17 R            34 i            51 z
- *        1 B            18 S            35 j            52 0
- *        2 C            19 T            36 k            53 1
- *        3 D            20 U            37 l            54 2
- *        4 E            21 V            38 m            55 3
- *        5 F            22 W            39 n            56 4
- *        6 G            23 X            40 o            57 5
- *        7 H            24 Y            41 p            58 6
- *        8 I            25 Z            42 q            59 7
- *        9 J            26 a            43 r            60 8
- *       10 K            27 b            44 s            61 9
- *       11 L            28 c            45 t            62 +
- *       12 M            29 d            46 u            63 /
- *       13 N            30 e            47 v
- *       14 O            31 f            48 w         (pad) =
- *       15 P            32 g            49 x
- *       16 Q            33 h            50 y
- */
+static const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+  "abcdefghijklmnopqrstuvwxyz0123456789+/";
 
-int
-base64_char_to_sextet(uint8_t c) {
-  switch(c) {
-  case 'A':
-    return 0;
-  case 'B':
-    return 1;
-  case 'C':
-    return 2;
-  case 'D':
-    return 3;
-  case 'E':
-    return 4;
-  case 'F':
-    return 5;
-  case 'G':
-    return 6;
-  case 'H':
-    return 7;
-  case 'I':
-    return 8;
-  case 'J':
-    return 9;
-  case 'K':
-    return 10;
-  case 'L':
-    return 11;
-  case 'M':
-    return 12;
-  case 'N':
-    return 13;
-  case 'O':
-    return 14;
-  case 'P':
-    return 15;
-  case 'Q':
-    return 16;
-  case 'R':
-    return 17;
-  case 'S':
-    return 18;
-  case 'T':
-    return 19;
-  case 'U':
-    return 20;
-  case 'V':
-    return 21;
-  case 'W':
-    return 22;
-  case 'X':
-    return 23;
-  case 'Y':
-    return 24;
-  case 'Z':
-    return 25;
-  case 'a':
-    return 26;
-  case 'b':
-    return 27;
-  case 'c':
-    return 28;
-  case 'd':
-    return 29;
-  case 'e':
-    return 30;
-  case 'f':
-    return 31;
-  case 'g':
-    return 32;
-  case 'h':
-    return 33;
-  case 'i':
-    return 34;
-  case 'j':
-    return 35;
-  case 'k':
-    return 36;
-  case 'l':
-    return 37;
-  case 'm':
-    return 38;
-  case 'n':
-    return 39;
-  case 'o':
-    return 40;
-  case 'p':
-    return 41;
-  case 'q':
-    return 42;
-  case 'r':
-    return 43;
-  case 's':
-    return 44;
-  case 't':
-    return 45;
-  case 'u':
-    return 46;
-  case 'v':
-    return 47;
-  case 'w':
-    return 48;
-  case 'x':
-    return 49;
-  case 'y':
-    return 50;
-  case 'z':
-    return 51;
-  case '0':
-    return 52;
-  case '1':
-    return 53;
-  case '2':
-    return 54;
-  case '3':
-    return 55;
-  case '4':
-    return 56;
-  case '5':
-    return 57;
-  case '6':
-    return 58;
-  case '7':
-    return 59;
-  case '8':
-    return 60;
-  case '9':
-    return 61;
-  case '+':
-    return 62;
-  case '/':
-    return 63;
-  case '=':
-    return 64;
-  default:
-    break;
- }
- return -1;
-}
+static int base64_block_to_octet_triple(char *out, char *in) {
+  unsigned char sextets[4] = {};
+  int j = 0;
+  int i;
 
-#ifdef INCLUDE_DEAD_CODE
-/*
- * base64_string_to_octet_string converts a hexadecimal string
- * of length 2 * len to a raw octet string of length len
- */
-
-int
-base64_string_to_octet_string(char *raw, char *base64, int len) {
-  uint8_t x;
-  int tmp;
-  int base64_len;
-
-  base64_len = 0;
-  while (base64_len < len) {
-    tmp = base64_char_to_sextet(base64[0]);
-    if (tmp == -1)
-      return base64_len;
-    x = (tmp << 6);
-    base64_len++;
-    tmp = base64_char_to_sextet(base64[1]);
-    if (tmp == -1)
-      return base64_len;
-    x |= (tmp & 0xffff);
-    base64_len++;
-    *raw++ = x;
-    base64 += 2;
+  for (i = 0; i < 4; i++) {
+    char *p = strchr(b64chars, in[i]);
+    if (p != NULL) sextets[i] = p - b64chars;
+    else j++;
   }
-  return base64_len;
+
+  out[0] = (sextets[0]<<2)|(sextets[1]>>4);
+  if (j < 2) out[1] = (sextets[1]<<4)|(sextets[2]>>2);
+  if (j < 1) out[2] = (sextets[2]<<6)|sextets[3];
+  return j;
 }
+
+int base64_string_to_octet_string(char *out, int *pad, char *in, int len) {
+  int k = 0;
+  int i = 0;
+  int j = 0;
+  if (len % 4 != 0) return 0;
+
+  while (i < len && j == 0) {
+    j = base64_block_to_octet_triple(out + k, in + i);
+    k += 3;
+    i += 4;
+  }
+  *pad = j;
+  return i;
+}
+
 #endif
diff --git a/test/rtp_decoder.c b/test/rtp_decoder.c
index ddc93d0..60b8d18 100644
--- a/test/rtp_decoder.c
+++ b/test/rtp_decoder.c
@@ -70,6 +70,7 @@
   int tag_size = 8;
   int gcm_on = 0;
   char *input_key = NULL;
+  int b64_input = 0;
   char key[MAX_KEY_LEN];
   struct bpf_program fp;
   char filter_exp[MAX_FILTER] = "";
@@ -77,6 +78,7 @@
   srtp_policy_t policy;
   err_status_t status;
   int len;
+  int expected_len;
   int do_list_mods = 0;
 
   fprintf(stderr, "Using %s [0x%x]\n", srtp_get_version_string(), srtp_get_version());
@@ -96,10 +98,8 @@
     }
     switch (c) {
 	case 'b':
-	  fprintf(stderr, "Decoding\n");
-		decode_sdes(optarg_s, input_key);
-		fprintf(stderr, "Decoded\n");
-		break;
+      b64_input = 1;
+      /* fall thru */
     case 'k':
       input_key = optarg_s;
       break;
@@ -275,16 +275,26 @@
     }
 
     /*
-     * read key from hexadecimal on command line into an octet string
+     * read key from hexadecimal or base64 on command line into an octet string
      */
-    len = hex_string_to_octet_string(key, input_key, policy.rtp.cipher_key_len*2);
-    
+    if (b64_input) {
+      int pad;
+      expected_len = policy.rtp.cipher_key_len*4/3;
+      len = base64_string_to_octet_string(key, &pad, input_key, expected_len);
+      if (pad != 0) {
+        fprintf(stderr, "error: padding in base64 unexpected\n");
+        exit(1);
+      }
+    } else {
+      expected_len = policy.rtp.cipher_key_len*2;
+      len = hex_string_to_octet_string(key, input_key, expected_len);
+    }
     /* check that hex string is the right length */
-    if (len < policy.rtp.cipher_key_len*2) {
+    if (len < expected_len) {
       fprintf(stderr, 
 	      "error: too few digits in key/salt "
-	      "(should be %d hexadecimal digits, found %d)\n",
-	      policy.rtp.cipher_key_len*2, len);
+	      "(should be %d digits, found %d)\n",
+	      expected_len, len);
       exit(1);    
     } 
     if (strlen(input_key) > policy.rtp.cipher_key_len*2) {
@@ -377,8 +387,8 @@
 	 "       -e <key size> use encryption (use 128 or 256 for key size)\n"
 	 "       -g Use AES-GCM mode (must be used with -e)\n"
 	 "       -t <tag size> Tag size to use in GCM mode (use 8 or 16)\n"
-	 "       -k <key>  sets the srtp master key\n"
-	 "       -b <key>  sets the srtp master key as base64\n"
+	 "       -k <key>  sets the srtp master key given in hexadecimal\n"
+	 "       -b <key>  sets the srtp master key given in base64\n"
 	 "       -l list debug modules\n"
 	 "       -d <debug> turn on debugging for module <debug>\n",
 	 string, string);
@@ -386,42 +396,6 @@
   
 }
 
-static const char b64chars[] =
-  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-unsigned char shiftb64(unsigned char c) {
-  char *p = strchr(b64chars, c);
-  assert(p);
-  return p-b64chars;
-}
-
-void decode_block(char *in, unsigned char *out) {
-  unsigned char shifts[4];
-  int i;
-
-  for (i = 0; i < 4; i++) {
-    shifts[i] = shiftb64(in[i]);
-  }
-
-  out[0] = (shifts[0]<<2)|(shifts[1]>>4);
-  out[1] = (shifts[1]<<4)|(shifts[2]>>2);
-  out[2] = (shifts[2]<<6)|shifts[3];
-}
-
-char *decode_sdes(char *in, char *out) {
-  int i;
-  size_t len = strlen((char *) in);
-  assert(len == 40);
-  unsigned char raw[30];
-
-  for (i = 0; 4*i < len; i++) {
-    decode_block(in+4*i, raw+3*i);
-  } 
-
-  memcpy(out, octet_string_hex_string(raw, 30), 60);
-  return out;
-}
-
 rtp_decoder_t
 rtp_decoder_alloc(void) {
   return (rtp_decoder_t)malloc(sizeof(rtp_decoder_ctx_t));
diff --git a/test/rtp_decoder.h b/test/rtp_decoder.h
index 832443d..3a92d8a 100644
--- a/test/rtp_decoder.h
+++ b/test/rtp_decoder.h
@@ -51,6 +51,7 @@
 #include "srtp_priv.h"
 #include "rtp_priv.h"
 #include "rtp.h"
+#include "datatypes.h"
 
 #define DEFAULT_RTP_OFFSET 42
 
diff --git a/test/rtpw.c b/test/rtpw.c
index 48c6649..17f27f2 100644
--- a/test/rtpw.c
+++ b/test/rtpw.c
@@ -161,6 +161,7 @@
   int tag_size = 8;
   int gcm_on = 0;
   char *input_key = NULL;
+  int b64_input = 0;
   char *address = NULL;
   char key[MAX_KEY_LEN];
   unsigned short port = 0;
@@ -168,6 +169,7 @@
   srtp_policy_t policy;
   err_status_t status;
   int len;
+  int expected_len;
   int do_list_mods = 0;
   uint32_t ssrc = 0xdeadbeef; /* ssrc value hardcoded for now */
 #ifdef RTPW_USE_WINSOCK2
@@ -196,11 +198,14 @@
 
   /* check args */
   while (1) {
-    c = getopt_s(argc, argv, "k:rsgt:ae:ld:");
+    c = getopt_s(argc, argv, "b:k:rsgt:ae:ld:");
     if (c == -1) {
       break;
     }
     switch (c) {
+	case 'b':
+      b64_input = 1;
+      /* fall thru */
     case 'k':
       input_key = optarg_s;
       break;
@@ -443,16 +448,26 @@
     }
 
     /*
-     * read key from hexadecimal on command line into an octet string
+     * read key from hexadecimal or base64 on command line into an octet string
      */
-    len = hex_string_to_octet_string(key, input_key, policy.rtp.cipher_key_len*2);
-    
+    if (b64_input) {
+        int pad;
+        expected_len = (policy.rtp.cipher_key_len*4)/3;
+        len = base64_string_to_octet_string(key, &pad, input_key, expected_len);
+        if (pad != 0) {
+          fprintf(stderr, "error: padding in base64 unexpected\n");
+          exit(1);
+        }
+    } else {
+        expected_len = policy.rtp.cipher_key_len*2;
+        len = hex_string_to_octet_string(key, input_key, expected_len);
+    }
     /* check that hex string is the right length */
-    if (len < policy.rtp.cipher_key_len*2) {
+    if (len < expected_len) {
       fprintf(stderr, 
 	      "error: too few digits in key/salt "
-	      "(should be %d hexadecimal digits, found %d)\n",
-	      policy.rtp.cipher_key_len*2, len);
+	      "(should be %d digits, found %d)\n",
+	      expected_len, len);
       exit(1);    
     } 
     if (strlen(input_key) > policy.rtp.cipher_key_len*2) {
@@ -630,7 +645,8 @@
 	 "       -e <key size> use encryption (use 128 or 256 for key size)\n"
 	 "       -g Use AES-GCM mode (must be used with -e)\n"
 	 "       -t <tag size> Tag size to use in GCM mode (use 8 or 16)\n"
-	 "       -k <key>  sets the srtp master key\n"
+	 "       -k <key>  sets the srtp master key given in hexadecimal\n"
+	 "       -b <key>  sets the srtp master key given in base64\n"
 	 "       -s act as rtp sender\n"
 	 "       -r act as rtp receiver\n"
 	 "       -l list debug modules\n"
diff --git a/test/rtpw_test.sh b/test/rtpw_test.sh
index c3c32ca..cd2aa6a 100755
--- a/test/rtpw_test.sh
+++ b/test/rtpw_test.sh
@@ -8,9 +8,9 @@
 DEST_PORT=9999
 DURATION=3
 
-key=2b2edc5034f61a72345ca5986d7bfd0189aa6dc2ecab32fd9af74df6dfc6
+key=Ky7cUDT2GnI0XKWYbXv9AYmqbcLsqzL9mvdN9t/G
 
-ARGS="-k $key -a -e 128"
+ARGS="-b $key -a -e 128"
 
 # First, we run "killall" to get rid of all existing rtpw processes.
 # This step also enables this script to clean up after itself; if this