All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] comp128: GSM algorithm (comp128) implementation.
@ 2017-10-03 16:32 James Prestwood
  2017-10-03 16:32 ` [PATCH 2/5] aes: small module for AES128 James Prestwood
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: James Prestwood @ 2017-10-03 16:32 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 12665 bytes --]

---
 src/comp128.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/comp128.h |  32 ++++++++
 2 files changed, 279 insertions(+)
 create mode 100644 src/comp128.c
 create mode 100644 src/comp128.h

diff --git a/src/comp128.c b/src/comp128.c
new file mode 100644
index 0000000..fe00cc4
--- /dev/null
+++ b/src/comp128.c
@@ -0,0 +1,247 @@
+/*! \file comp128.c
+ *  COMP128 v1; common/old GSM Authentication Algorithm (A3/A8).
+ *
+ * This code is inspired by original code from :
+ *  Marc Briceno <marc@scard.org>, Ian Goldberg <iang@cs.berkeley.edu>,
+ *  and David Wagner <daw@cs.berkeley.edu>
+ *
+ * But it has been fully rewritten from various PDFs found online describing
+ * the algorithm because the licence of the code referenced above was unclear.
+ * A comment snippet from the original code is included below, it describes
+ * where the doc came from and how the algorithm was reverse engineered.
+ *
+ * This code derived from a leaked document from the GSM standards.
+ * Some missing pieces were filled in by reverse-engineering a working SIM.
+ * We have verified that this is the correct COMP128 algorithm.
+ *
+ * The first page of the document identifies it as
+ *
+ *  _Technical Information: GSM System Security Study_.
+ *  10-1617-01, 10th June 1988.
+ *
+ * The bottom of the title page is marked
+ *
+ *  Racal Research Ltd.
+ *  Worton Drive, Worton Grange Industrial Estate,
+ *  Reading, Berks. RG2 0SB, England.
+ *  Telephone: Reading (0734) 868601   Telex: 847152
+ *
+ * The relevant bits are in Part I, Section 20 (pages 66--67).  Enjoy!
+ *
+ * Note: There are three typos in the spec (discovered by
+ * reverse-engineering).
+ * - First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read
+ *   "z = (2 * x[m] + x[n]) mod 2^(9-j)".
+ * - Second, the "k" loop in the "Form bits from bytes" section is severely
+ *   botched: the k index should run only from 0 to 3, and clearly the range
+ *   on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8,
+ *   to be consistent with the subsequent section).
+ * - Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as
+ *   claimed in the document.  (And the document doesn't specify how Kc is
+ *   derived, but that was also easily discovered with reverse engineering.)
+ * All of these typos have been corrected in the following code.
+ */
+/*
+ * (C) 2009 by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+/*! \addtogroup auth
+ *  @{
+ * \file comp128.c */
+
+/* The compression tables (just copied ...) */
+static const uint8_t table_0[512] = {
+ 102, 177, 186, 162,   2, 156, 112,  75,  55,  25,   8,  12, 251, 193, 246, 188,
+ 109, 213, 151,  53,  42,  79, 191, 115, 233, 242, 164, 223, 209, 148, 108, 161,
+ 252,  37, 244,  47,  64, 211,   6, 237, 185, 160, 139, 113,  76, 138,  59,  70,
+  67,  26,  13, 157,  63, 179, 221,  30, 214,  36, 166,  69, 152, 124, 207, 116,
+ 247, 194,  41,  84,  71,   1,  49,  14,  95,  35, 169,  21,  96,  78, 215, 225,
+ 182, 243,  28,  92, 201, 118,   4,  74, 248, 128,  17,  11, 146, 132, 245,  48,
+ 149,  90, 120,  39,  87, 230, 106, 232, 175,  19, 126, 190, 202, 141, 137, 176,
+ 250,  27, 101,  40, 219, 227,  58,  20,  51, 178,  98, 216, 140,  22,  32, 121,
+  61, 103, 203,  72,  29, 110,  85, 212, 180, 204, 150, 183,  15,  66, 172, 196,
+  56, 197, 158,   0, 100,  45, 153,   7, 144, 222, 163, 167,  60, 135, 210, 231,
+ 174, 165,  38, 249, 224,  34, 220, 229, 217, 208, 241,  68, 206, 189, 125, 255,
+ 239,  54, 168,  89, 123, 122,  73, 145, 117, 234, 143,  99, 129, 200, 192,  82,
+ 104, 170, 136, 235,  93,  81, 205, 173, 236,  94, 105,  52,  46, 228, 198,   5,
+  57, 254,  97, 155, 142, 133, 199, 171, 187,  50,  65, 181, 127, 107, 147, 226,
+ 184, 218, 131,  33,  77,  86,  31,  44,  88,  62, 238,  18,  24,  43, 154,  23,
+  80, 159, 134, 111,   9, 114,   3,  91,  16, 130,  83,  10, 195, 240, 253, 119,
+ 177, 102, 162, 186, 156,   2,  75, 112,  25,  55,  12,   8, 193, 251, 188, 246,
+ 213, 109,  53, 151,  79,  42, 115, 191, 242, 233, 223, 164, 148, 209, 161, 108,
+  37, 252,  47, 244, 211,  64, 237,   6, 160, 185, 113, 139, 138,  76,  70,  59,
+  26,  67, 157,  13, 179,  63,  30, 221,  36, 214,  69, 166, 124, 152, 116, 207,
+ 194, 247,  84,  41,   1,  71,  14,  49,  35,  95,  21, 169,  78,  96, 225, 215,
+ 243, 182,  92,  28, 118, 201,  74,   4, 128, 248,  11,  17, 132, 146,  48, 245,
+  90, 149,  39, 120, 230,  87, 232, 106,  19, 175, 190, 126, 141, 202, 176, 137,
+  27, 250,  40, 101, 227, 219,  20,  58, 178,  51, 216,  98,  22, 140, 121,  32,
+ 103,  61,  72, 203, 110,  29, 212,  85, 204, 180, 183, 150,  66,  15, 196, 172,
+ 197,  56,   0, 158,  45, 100,   7, 153, 222, 144, 167, 163, 135,  60, 231, 210,
+ 165, 174, 249,  38,  34, 224, 229, 220, 208, 217,  68, 241, 189, 206, 255, 125,
+  54, 239,  89, 168, 122, 123, 145,  73, 234, 117,  99, 143, 200, 129,  82, 192,
+ 170, 104, 235, 136,  81,  93, 173, 205,  94, 236,  52, 105, 228,  46,   5, 198,
+ 254,  57, 155,  97, 133, 142, 171, 199,  50, 187, 181,  65, 107, 127, 226, 147,
+ 218, 184,  33, 131,  86,  77,  44,  31,  62,  88,  18, 238,  43,  24,  23, 154,
+ 159,  80, 111, 134, 114,   9,  91,   3, 130,  16,  10,  83, 240, 195, 119, 253,
+}, table_1[256] = {
+  19,  11,  80, 114,  43,   1,  69,  94,  39,  18, 127, 117,  97,   3,  85,  43,
+  27, 124,  70,  83,  47,  71,  63,  10,  47,  89,  79,   4,  14,  59,  11,   5,
+  35, 107, 103,  68,  21,  86,  36,  91,  85, 126,  32,  50, 109,  94, 120,   6,
+  53,  79,  28,  45,  99,  95,  41,  34,  88,  68,  93,  55, 110, 125, 105,  20,
+  90,  80,  76,  96,  23,  60,  89,  64, 121,  56,  14,  74, 101,   8,  19,  78,
+  76,  66, 104,  46, 111,  50,  32,   3,  39,   0,  58,  25,  92,  22,  18,  51,
+  57,  65, 119, 116,  22, 109,   7,  86,  59,  93,  62, 110,  78,  99,  77,  67,
+  12, 113,  87,  98, 102,   5,  88,  33,  38,  56,  23,   8,  75,  45,  13,  75,
+  95,  63,  28,  49, 123, 120,  20, 112,  44,  30,  15,  98, 106,   2, 103,  29,
+  82, 107,  42, 124,  24,  30,  41,  16, 108, 100, 117,  40,  73,  40,   7, 114,
+  82, 115,  36, 112,  12, 102, 100,  84,  92,  48,  72,  97,   9,  54,  55,  74,
+ 113, 123,  17,  26,  53,  58,   4,   9,  69, 122,  21, 118,  42,  60,  27,  73,
+ 118, 125,  34,  15,  65, 115,  84,  64,  62,  81,  70,   1,  24, 111, 121,  83,
+ 104,  81,  49, 127,  48, 105,  31,  10,   6,  91,  87,  37,  16,  54, 116, 126,
+  31,  38,  13,   0,  72, 106,  77,  61,  26,  67,  46,  29,  96,  37,  61,  52,
+ 101,  17,  44, 108,  71,  52,  66,  57,  33,  51,  25,  90,   2, 119, 122,  35,
+}, table_2[128] = {
+ 52,  50,  44,   6,  21,  49,  41,  59,  39,  51,  25,  32,  51,  47,  52,  43,
+ 37,   4,  40,  34,  61,  12,  28,   4,  58,  23,   8,  15,  12,  22,   9,  18,
+ 55,  10,  33,  35,  50,   1,  43,   3,  57,  13,  62,  14,   7,  42,  44,  59,
+ 62,  57,  27,   6,   8,  31,  26,  54,  41,  22,  45,  20,  39,   3,  16,  56,
+ 48,   2,  21,  28,  36,  42,  60,  33,  34,  18,   0,  11,  24,  10,  17,  61,
+ 29,  14,  45,  26,  55,  46,  11,  17,  54,  46,   9,  24,  30,  60,  32,   0,
+ 20,  38,   2,  30,  58,  35,   1,  16,  56,  40,  23,  48,  13,  19,  19,  27,
+ 31,  53,  47,  38,  63,  15,  49,   5,  37,  53,  25,  36,  63,  29,   5,   7,
+}, table_3[64] = {
+  1,   5,  29,   6,  25,   1,  18,  23,  17,  19,   0,   9,  24,  25,   6,  31,
+ 28,  20,  24,  30,   4,  27,   3,  13,  15,  16,  14,  18,   4,   3,   8,   9,
+ 20,   0,  12,  26,  21,   8,  28,   2,  29,   2,  15,   7,  11,  22,  14,  10,
+ 17,  21,  12,  30,  26,  27,  16,  31,  11,   7,  13,  23,  10,   5,  22,  19,
+}, table_4[32] = {
+ 15,  12,  10,   4,   1,  14,  11,   7,   5,   0,  14,   7,   1,   2,  13,   8,
+ 10,   3,   4,   9,   6,   0,   3,   2,   5,   6,   8,   9,  11,  13,  15,  12,
+};
+
+static const uint8_t *_comp128_table[5] = { table_0, table_1, table_2, table_3, table_4 };
+
+
+static inline void
+_comp128_compression_round(uint8_t *x, int n, const uint8_t *tbl)
+{
+    int i, j, m, a, b, y, z;
+    m = 4 - n;
+    for (i=0; i<(1<<n); i++)
+        for (j=0; j<(1<<m); j++) {
+            a = j + i * (2<<m);
+            b = a + (1<<m);
+            y = (x[a] + (x[b]<<1)) & ((32<<m)-1);
+            z = ((x[a]<<1) + x[b]) & ((32<<m)-1);
+            x[a] = tbl[y];
+            x[b] = tbl[z];
+        }
+}
+
+static inline void
+_comp128_compression(uint8_t *x)
+{
+    int n;
+    for (n=0; n<5; n++)
+        _comp128_compression_round(x, n, _comp128_table[n]);
+}
+
+static inline void
+_comp128_bitsfrombytes(uint8_t *x, uint8_t *bits)
+{
+    int i;
+    memset(bits, 0x00, 128);
+    for (i=0; i<128; i++)
+        if (x[i>>2] & (1<<(3-(i&3))))
+            bits[i] = 1;
+}
+
+static inline void
+_comp128_permutation(uint8_t *x, uint8_t *bits)
+{
+    int i;
+    memset(&x[16], 0x00, 16);
+    for (i=0; i<128; i++)
+        x[(i>>3)+16] |= bits[(i*17) & 127] << (7-(i&7));
+}
+
+/*! Perform COMP128v1 algorithm
+ *  \param[in] ki Secret Key K(i) of subscriber
+ *  \param[in] rand Random Challenge
+ *  \param[out] sres user-supplied buffer for storing computed SRES value
+ *  \param[out] kc user-supplied buffer for storing computed Kc value */
+void
+comp128v1(const uint8_t *ki, const uint8_t *rand, uint8_t *sres, uint8_t *kc)
+{
+    int i;
+    uint8_t x[32], bits[128];
+
+    /* x[16-31] = RAND */
+    memcpy(&x[16], rand, 16);
+
+    /* Round 1-7 */
+    for (i=0; i<7; i++) {
+        /* x[0-15] = Ki */
+        memcpy(x, ki, 16);
+
+        /* Compression */
+        _comp128_compression(x);
+
+        /* FormBitFromBytes */
+        _comp128_bitsfrombytes(x, bits);
+
+        /* Permutation */
+        _comp128_permutation(x, bits);
+    }
+
+    /* Round 8 (final) */
+        /* x[0-15] = Ki */
+    memcpy(x, ki, 16);
+
+        /* Compression */
+    _comp128_compression(x);
+
+    /* Output stage */
+    for (i=0; i<8; i+=2)
+        sres[i>>1] = x[i]<<4 | x[i+1];
+
+    for (i=0; i<12; i+=2)
+        kc[i>>1] = (x[i + 18] << 6) |
+                   (x[i + 19] << 2) |
+                   (x[i + 20] >> 2);
+
+    kc[6] = (x[30]<<6) | (x[31]<<2);
+    kc[7] = 0;
+}
+
+
+/*! Perform COMP128v1 algorithm
+ *  \param[in] ki Secret Key K(i) of subscriber
+ *  \param[in] rand Random Challenge
+ *  \param[out] sres user-supplied buffer for storing computed SRES value
+ *  \param[out] kc user-supplied buffer for storing computed Kc value */
+void
+comp128(const uint8_t *ki, const uint8_t *rand, uint8_t *sres, uint8_t *kc)
+{
+    comp128v1(ki, rand, sres, kc);
+}
diff --git a/src/comp128.h b/src/comp128.h
new file mode 100644
index 0000000..372a39e
--- /dev/null
+++ b/src/comp128.h
@@ -0,0 +1,32 @@
+/****************************************************************************
+**
+** This file is part of the Qt Extended Opensource Package.
+**
+** Copyright (C) 2017  Intel Corporation. All rights reserved.
+**
+** This file may be used under the terms of the GNU General Public License
+** version 2.0 as published by the Free Software Foundation and appearing
+** in the file LICENSE.GPL included in the packaging of this file.
+**
+** Please review the following information to ensure GNU General Public
+** Licensing requirements will be met:
+**     http://www.fsf.org/licensing/licenses/info/GPLv2.html.
+**
+**
+****************************************************************************/
+
+#ifndef COMP128_H
+#define COMP128_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void comp128(const uint8_t *ki, const uint8_t *rand, uint8_t *sres,
+        uint8_t *kc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COMP128_H */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/5] aes: small module for AES128
  2017-10-03 16:32 [PATCH 1/5] comp128: GSM algorithm (comp128) implementation James Prestwood
@ 2017-10-03 16:32 ` James Prestwood
  2017-10-03 16:32 ` [PATCH 3/5] simauth: Added SimAuth class for GSM/UMTS authentication James Prestwood
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: James Prestwood @ 2017-10-03 16:32 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 4688 bytes --]

A new module with AES128 functionality using kernel crypto
APIs. SimAuth module requires AES128 for UMTS authenticate
command.
---
 src/aes.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/aes.h |  32 +++++++++++++++++
 2 files changed, 153 insertions(+)
 create mode 100644 src/aes.c
 create mode 100644 src/aes.h

diff --git a/src/aes.c b/src/aes.c
new file mode 100644
index 0000000..921ec79
--- /dev/null
+++ b/src/aes.c
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** This file is part of the Qt Extended Opensource Package.
+**
+** Copyright (C) 2017  Intel Corporation. All rights reserved.
+**
+** This file may be used under the terms of the GNU General Public License
+** version 2.0 as published by the Free Software Foundation and appearing
+** in the file LICENSE.GPL included in the packaging of this file.
+**
+** Please review the following information to ensure GNU General Public
+** Licensing requirements will be met:
+**     http://www.fsf.org/licensing/licenses/info/GPLv2.html.
+**
+**
+****************************************************************************/
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/socket.h>
+#include <alloca.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "aes.h"
+
+#ifndef AF_ALG
+#define AF_ALG	38
+#define PF_ALG	AF_ALG
+#endif
+
+#ifndef HAVE_LINUX_IF_ALG_H
+struct sockaddr_alg {
+    uint16_t    salg_family;
+    uint8_t     salg_type[14];
+    uint32_t    salg_feat;
+    uint32_t    salg_mask;
+    uint8_t     salg_name[64];
+};
+
+#define ALG_SET_KEY     1
+#define ALG_SET_OP      3
+#define ALG_OP_ENCRYPT  1
+#else
+#include <linux/if_alg.h>
+#endif
+
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
+bool aes_encrypt(const uint8_t *key, size_t key_len, const uint8_t *in,
+        uint8_t *out, size_t len)
+{
+    uint32_t op = ALG_OP_ENCRYPT;
+    char *msg_buf;
+    size_t msg_size;
+    struct msghdr msg;
+    struct cmsghdr *c_msg;
+    ssize_t result;
+
+    struct sockaddr_alg sa = {
+            .salg_family = AF_ALG,
+            .salg_type = "skcipher",
+            .salg_name = "ecb(aes)"
+    };
+
+    struct iovec iov = {
+            .iov_base = (void *) in,
+            .iov_len = len
+    };
+
+    int sock = socket(AF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
+    if (bind(sock, (struct sockaddr *)&sa, sizeof(sa))) {
+        close(sock);
+        return 0;
+    }
+    if (setsockopt(sock, SOL_ALG, ALG_SET_KEY, key, key_len)) {
+        close(sock);
+        return 0;
+    }
+
+    int cipher = accept4(sock, NULL, 0, SOCK_CLOEXEC);
+    if (cipher == -1) {
+        close(sock);
+        return 0;
+    }
+    close(sock);
+
+    msg_size = CMSG_SPACE(sizeof(op));
+
+    msg_buf = alloca(msg_size);
+
+    memset(msg_buf, 0, msg_size);
+    memset(&msg, 0, sizeof(msg));
+
+    msg.msg_iov = &iov;
+    msg.msg_control = msg_buf;
+    msg.msg_controllen = msg_size;
+    msg.msg_iovlen = 1;
+
+    c_msg = CMSG_FIRSTHDR(&msg);
+    c_msg->cmsg_level = SOL_ALG;
+    c_msg->cmsg_type = ALG_SET_OP;
+    c_msg->cmsg_len = CMSG_LEN(sizeof(op));
+    memcpy(CMSG_DATA(c_msg), &op, sizeof(op));
+
+    result = sendmsg(cipher, &msg, 0);
+    if (result < 0) {
+        return 0;
+    }
+
+    result = read(cipher, out, len);
+    if (result < 0) {
+        return 0;
+    }
+
+    return 1;
+}
+
diff --git a/src/aes.h b/src/aes.h
new file mode 100644
index 0000000..278e0cc
--- /dev/null
+++ b/src/aes.h
@@ -0,0 +1,32 @@
+/****************************************************************************
+**
+** This file is part of the Qt Extended Opensource Package.
+**
+** Copyright (C) 2017  Intel Corporation. All rights reserved.
+**
+** This file may be used under the terms of the GNU General Public License
+** version 2.0 as published by the Free Software Foundation and appearing
+** in the file LICENSE.GPL included in the packaging of this file.
+**
+** Please review the following information to ensure GNU General Public
+** Licensing requirements will be met:
+**     http://www.fsf.org/licensing/licenses/info/GPLv2.html.
+**
+**
+****************************************************************************/
+
+#ifndef CIPHER_H
+#define CIPHER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool aes_encrypt(const uint8_t *key, size_t key_len, const uint8_t *in,
+        uint8_t *out, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CIPHER_H */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/5] simauth: Added SimAuth class for GSM/UMTS authentication
  2017-10-03 16:32 [PATCH 1/5] comp128: GSM algorithm (comp128) implementation James Prestwood
  2017-10-03 16:32 ` [PATCH 2/5] aes: small module for AES128 James Prestwood
@ 2017-10-03 16:32 ` James Prestwood
  2017-10-03 16:32 ` [PATCH 3/5] simauth: Added SimAuth class for GSM/UMTS auth James Prestwood
  2017-10-03 16:32 ` [PATCH 4/5] make: add simauth/aes/comp128 to build James Prestwood
  3 siblings, 0 replies; 7+ messages in thread
From: James Prestwood @ 2017-10-03 16:32 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 15429 bytes --]

SimAuth class is used to parse/respond to several AT commands. In
order to simulate running a SIMs GSM/UMTS authentication algorithms.

The class is initialized if the XML contains a "simauth" tag, which should
contain the secret key "ki" value, "opc" and a list of "aid" tags.

Implemented AT commands:

AT+CUAD: List available SIM applications (USIM or ISIM)
AT+CCHO: Open logical channel
AT+CGLA: Run either GSM/UMTS algorithm
AT+CCHC: Close logical channel

The GSM algorithm uses COMP128v1 (src/comp128.c), which generates
SRES and KC.

The UMTS algorithm uses the "Milenage" algorithm which generates
RES, CK and IK, or AUTS in case of sync failure.
---
 src/simauth.cpp | 414 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/simauth.h   | 105 ++++++++++++++
 2 files changed, 519 insertions(+)
 create mode 100644 src/simauth.cpp
 create mode 100644 src/simauth.h

diff --git a/src/simauth.cpp b/src/simauth.cpp
new file mode 100644
index 0000000..ce8263d
--- /dev/null
+++ b/src/simauth.cpp
@@ -0,0 +1,414 @@
+/****************************************************************************
+**
+** This file is part of the Qt Extended Opensource Package.
+**
+** Copyright (C) 2017  Intel Corporation. All rights reserved.
+**
+** This file may be used under the terms of the GNU General Public License
+** version 2.0 as published by the Free Software Foundation and appearing
+** in the file LICENSE.GPL included in the packaging of this file.
+**
+** Please review the following information to ensure GNU General Public
+** Licensing requirements will be met:
+**     http://www.fsf.org/licensing/licenses/info/GPLv2.html.
+**
+**
+****************************************************************************/
+
+#include "simauth.h"
+#include <qatutils.h>
+#include <qsimcontrolevent.h>
+
+extern "C" {
+#include "comp128.h"
+#include "aes.h"
+}
+
+#define QSTRING_TO_BUF(s) \
+    (uint8_t *)QByteArray::fromHex( s.toUtf8().data() ).data()
+
+SimAuth::SimAuth( QObject *parent, SimXmlNode& n )
+    : QObject( parent )
+{
+    SimXmlNode *child = n.children;
+
+    _ki = n.getAttribute( "ki" );
+    _opc = n.getAttribute( "opc" );
+    _session_start = 257;
+
+    _aid_list = QStringList();
+
+    // parse list of <aid> </aid>
+    while (child) {
+        if ( child->tag == "aid" )
+            _aid_list += QStringList( child->contents );
+
+        child = child->next;
+    }
+}
+
+SimAuth::~SimAuth()
+{
+}
+
+bool SimAuth::command( const QString& cmd )
+{
+    if ( cmd.startsWith( "AT+CUAD") ) {
+        QString response( "+CUAD: " );
+
+        if ( cmd.contains("=?") ) {
+            emit send( "OK" );
+            return true;
+        }
+
+        foreach ( const QString &str, _aid_list )
+            response += str;
+
+        response.append( "\n\nOK" );
+
+        emit send( response );
+    } else if ( cmd.startsWith( "AT+CCHO" ) ) {
+        QString aid;
+        int session_id = -1;
+
+        if ( !cmd.contains("=") ) {
+            emit send( "ERROR" );
+            return true;
+        }
+
+        if ( cmd.contains("=?") ) {
+            emit send( "OK" );
+            return true;
+        }
+
+        aid = cmd.split('=')[1];
+        aid = aid.replace("\"", "");
+
+        foreach ( const QString &str, _aid_list ) {
+            if ( str.contains( aid ) ) {
+                session_id = openChannel( aid );
+                break;
+            }
+        }
+
+        if ( session_id == -1 ) {
+            emit send( "ERROR" );
+            return true;
+        }
+
+        emit send( QString( "+CCHO: %1\n\nOK" ).arg(session_id, 0, 10) );
+    } else if ( cmd.startsWith( "AT+CGLA" ) ) {
+        QString aid;
+        QString data;
+        QString command;
+        QString parameters;
+        QString response;
+        enum CmdType type;
+        int session_id = -1;
+
+        if ( !cmd.contains("=") ) {
+            emit send( "ERROR" );
+            return true;
+        }
+
+        if ( cmd.contains("=?") ) {
+            emit send( "OK" );
+            return true;
+        }
+
+        data = cmd.split('=')[1];
+        session_id = data.split(',')[0].toInt();
+
+        if (!getAidFromSession( session_id, aid )) {
+            emit send( "ERROR" );
+            return true;
+        }
+
+        data = data.split(',')[2].replace("\"", "");
+        parameters = data.mid(10);
+
+        type = checkCommand( data, aid );
+
+        if (type == CMD_TYPE_GSM_AUTH) {
+            QString sres, kc;
+            QString rand = parameters.mid(2, 32);
+
+            gsmAuthenticate( rand, sres, kc );
+
+            response = QString( "+CGLA: 32,\"04 %1 08 %2 \"\n\nOK" )
+                    .arg( sres, kc );
+            response.replace( " ", "");
+
+        } else if (type == CMD_TYPE_UMTS_AUTH) {
+            enum UmtsStatus status;
+            QString res, ck, ik, auts;
+            QString rand = parameters.mid(2, 32);
+            QString autn = parameters.mid(36, 32);
+
+            status = umtsAuthenticate( rand, autn, res, ck, ik, auts );
+
+            response = QString("+CGLA: ");
+
+            QString test;
+
+            switch (status) {
+            case UMTS_OK:
+                response += QString( "88,\"DB08 %1 10 %2 10 %3\"\n\nOK" )
+                        .arg( res, ck, ik );
+                response.replace( " ", "" );
+
+                break;
+            case UMTS_INVALID_MAC:
+                response += QString( "4,\"%1\"\n\nOK")
+                        .arg( CMD_TYPE_APP_ERROR, 0, 16 );
+
+                break;
+            case UMTS_SYNC_FAILURE:
+                response == QString( "34,\"DC10 %1 \"\n\nOK" ).arg( auts );
+                response.replace( " ", "" );
+
+                break;
+            case UMTS_ERROR:
+                response = QString( "ERROR" );
+
+                break;
+            }
+        } else {
+            response = QString("+CGLA: 4,\"%1\"\n\nOK").arg(type, 0, 16);
+        }
+
+        emit send( response );
+    } else if ( cmd.startsWith( "AT+CCHC" ) ) {
+        int session_id = -1;
+
+        if ( !cmd.contains("=") ) {
+            emit send( "ERROR" );
+            return true;
+        }
+
+        if ( cmd.contains("=?") ) {
+            emit send( "OK" );
+            return true;
+        }
+
+        session_id = cmd.split('=')[1].toInt();
+
+        closeChannel(session_id);
+
+        emit send( "OK" );
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+int SimAuth::openChannel( QString aid )
+{
+    if ( _logical_channels.size() >= MAX_LOGICAL_CHANNELS )
+        return -1;
+
+    _logical_channels.insert( _session_start, aid );
+
+    return _session_start++;
+}
+
+void SimAuth::closeChannel( int session_id )
+{
+    _logical_channels.remove( session_id );
+}
+
+bool SimAuth::getAidFromSession( int session_id, QString& aid )
+{
+    if ( _logical_channels.contains( session_id ) ) {
+        aid = _logical_channels[session_id];
+        return true;
+    }
+
+    return false;
+}
+
+enum AidType SimAuth::getAidType( QString aid )
+{
+    if ( aid.mid(10, 4) == "1004" )
+        return AID_TYPE_ISIM;
+    else if ( aid.mid(10, 4) == "1002")
+        return AID_TYPE_USIM;
+
+    return AID_TYPE_UNKNOWN;
+}
+
+
+enum CmdType SimAuth::checkCommand( QString command, QString aid )
+{
+    QString cls = command.mid(0, 2);
+    QString ins = command.mid(2, 2);
+    QString p1 = command.mid(4, 2);
+    QString p2 = command.mid(6, 2);
+    QString lc = command.mid(8, 2);
+    AidType type = getAidType( aid );
+
+    if ( cls != "00" )
+        return CMD_TYPE_UNSUPPORTED_CLS;
+
+    if ( ins != "88" )
+        return CMD_TYPE_UNSUPPORTED_INS;
+
+    if ( p1 != "00" )
+        return CMD_TYPE_INCORRECT_P2_P1;
+
+    if ( p2 == "80" ) {
+        if ( lc != "11" )
+            return CMD_TYPE_WRONG_LENGTH;
+
+        if ( !(type == AID_TYPE_USIM || type == AID_TYPE_ISIM) )
+            return CMD_TYPE_APP_ERROR;
+
+        return CMD_TYPE_GSM_AUTH;
+    } else if ( p2 == "81" ) {
+        if ( lc != "22" )
+            return CMD_TYPE_WRONG_LENGTH;
+
+        if ( type != AID_TYPE_ISIM )
+            return CMD_TYPE_APP_ERROR;
+
+        return CMD_TYPE_UMTS_AUTH;
+    } else {
+        return CMD_TYPE_UNKNOWN;
+    }
+}
+
+void SimAuth::gsmAuthenticate( QString rand, QString &sres,
+        QString &kc )
+{
+    uint8_t *ki = QSTRING_TO_BUF( _ki );
+    uint8_t *_rand = QSTRING_TO_BUF( rand );
+    uint8_t _sres[4];
+    uint8_t _kc[8];
+
+    comp128( ki, _rand, _sres, _kc );
+
+    sres = QByteArray( (const char *)_sres, 4 ).toHex();
+    kc = QByteArray( (const char *)_kc, 8 ).toHex();
+}
+
+/*
+ * Helper to XOR an array
+ * to - result of XOR array
+ * a - array 1
+ * b - array 2
+ * len - size of aray
+ */
+#define XOR(to, a, b, len) \
+    for (i = 0; i < len; i++) { \
+        to[i] = a[i] ^ b[i]; \
+    }
+
+enum UmtsStatus SimAuth::umtsAuthenticate( QString rand, QString autn,
+        QString &res, QString &ck, QString &ik, QString &auts )
+{
+    int i;
+
+    uint8_t *ki = QSTRING_TO_BUF( _ki );
+    uint8_t *_rand = QSTRING_TO_BUF( rand );
+    uint8_t *_autn = QSTRING_TO_BUF( autn );
+    uint8_t *opc = QSTRING_TO_BUF( _opc );
+
+    uint8_t ak[6];
+    uint8_t sqn[6];
+    uint8_t amf[2];
+    uint8_t mac[8];
+    uint8_t _res[8];
+    uint8_t _ck[16];
+    uint8_t _ik[16];
+
+    uint8_t temp[16];
+    uint8_t out1[16];
+    uint8_t out2[16];
+    uint8_t in1[16];
+    uint8_t tmp1[16];
+    uint8_t tmp2[16];
+
+    // copy out AMF/MAC from AUTN
+    memcpy(amf, _autn + 6, 2);
+    memcpy(mac, _autn + 8, 8);
+
+    // TEMP = AES[RAND ^ OPc]
+    XOR(temp, _rand, opc, 16);
+    aes_encrypt(ki, 16, temp, temp, 16);
+
+    // f2 algorithm
+    // OUT2 == AES[(TEMP ^ OPc) ^ c2] ^ OPc]
+    XOR(tmp1, temp, opc, 16);
+    tmp1[15] ^= 1;
+    aes_encrypt(ki, 16, tmp1, tmp1, 16);
+    XOR(out2, tmp1, opc, 16);
+
+    // AK is first 6 bytes of OUT2
+    memcpy(ak, out2, 6);
+    // RES is last 8 bytes of OUT2
+    memcpy(_res, out2 + 8, 8);
+
+    // get SQN, first 6 bytes of AUTN are SQN^AK, so (SQN^AK)^AK = SQN
+    XOR(sqn, _autn, ak, 6);
+
+    // f1 algorithm
+    // setup IN1
+    memcpy(in1, sqn, 6);
+    memcpy(in1 + 6, amf, 2);
+    memcpy(in1 + 8, sqn, 6);
+    memcpy(in1 + 14, amf, 2);
+
+    for (i = 0; i < 16; i++)
+        tmp1[(i + 8) % 16] = in1[i] ^ opc[i];
+
+    /* tmp2 = TEMP ^ tmp1 */
+    XOR(tmp2, temp, tmp1, 16);
+    /* tmp2 = E[tmp2]k */
+    aes_encrypt(ki, 16, tmp2, tmp1, 16);
+    /* out1 = OUT1 = tmp1 ^ opc */
+    XOR(out1, tmp1, opc, 16);
+
+    if (memcmp(_autn + 8, out1, 8)) {
+        // f5* algorithm
+        // rot(TEMP ^ OPC, r5)
+        for (i = 0; i < 16; i++)
+            tmp1[(i + 4) % 16] = temp[i] ^ opc[i];
+
+        // XOR with c5
+        tmp1[15] ^= 1 << 3;
+        aes_encrypt(ki, 16, tmp1, tmp1, 16);
+        // XOR with OPc
+        XOR(tmp1, opc, tmp1, 16);
+
+        auts = QByteArray( (const char *)tmp1, 16 ).toHex();
+
+        return UMTS_INVALID_MAC;
+    }
+
+    // f3 algorithm
+    for (i = 0; i < 16; i++)
+        tmp1[(i + 12) % 16] = temp[i] ^ opc[i];
+
+    /* tmp1 ^ c3. c3 at bit 126 == 1 */
+    tmp1[15] ^= 1 << 1;
+    aes_encrypt(ki, 16, tmp1, _ck, 16);
+    /* ck ^ opc */
+    XOR(_ck, _ck, opc, 16);
+
+    // f4 algorithm
+    for (i = 0; i < 16; i++)
+        tmp1[(i + 8) % 16] = temp[i] ^ opc[i];
+
+    /* tmp1 ^ c4. c4@bit 125 == 1 */
+    tmp1[15] ^= 1 << 2;
+    aes_encrypt(ki, 16, tmp1, _ik, 16);
+    /* ik ^ opc */
+    XOR(_ik, _ik, opc, 16);
+
+    res = QByteArray( (const char *)_res, 8 ).toHex();
+    ck = QByteArray( (const char *)_ck, 16 ).toHex();
+    ik = QByteArray( (const char *)_ik, 16 ).toHex();
+
+    return UMTS_OK;
+}
diff --git a/src/simauth.h b/src/simauth.h
new file mode 100644
index 0000000..eb733f6
--- /dev/null
+++ b/src/simauth.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** This file is part of the Qt Extended Opensource Package.
+**
+** Copyright (C) 2017  Intel Corporation. All rights reserved.
+**
+** This file may be used under the terms of the GNU General Public License
+** version 2.0 as published by the Free Software Foundation and appearing
+** in the file LICENSE.GPL included in the packaging of this file.
+**
+** Please review the following information to ensure GNU General Public
+** Licensing requirements will be met:
+**     http://www.fsf.org/licensing/licenses/info/GPLv2.html.
+**
+**
+****************************************************************************/
+
+#ifndef SIMAUTH_H
+#define SIMAUTH_H
+
+#include "phonesim.h"
+
+#define MAX_LOGICAL_CHANNELS    4
+
+enum AidType {
+    AID_TYPE_USIM,
+    AID_TYPE_ISIM,
+    AID_TYPE_UNKNOWN
+};
+
+/*
+ * Some common errors
+ */
+enum CmdType {
+    CMD_TYPE_GSM_AUTH = 0,
+    CMD_TYPE_UMTS_AUTH = 1,
+    CMD_TYPE_UNSUPPORTED_CLS = 0x6E00,
+    CMD_TYPE_UNSUPPORTED_INS = 0x6D00,
+    CMD_TYPE_INCORRECT_P2_P1 = 0x6A86,
+    CMD_TYPE_WRONG_LENGTH = 0x6700,
+    CMD_TYPE_APP_ERROR = 0x9862,
+    CMD_TYPE_UNKNOWN = 0xFFFF
+};
+
+enum UmtsStatus {
+    UMTS_OK,            // Success
+    UMTS_INVALID_MAC,   // MAC did not match AUTN parameter
+    UMTS_SYNC_FAILURE,  // SQN did not match
+    UMTS_ERROR          // Any other error
+};
+
+class SimAuth : public QObject
+{
+    Q_OBJECT
+public:
+    SimAuth( QObject *parent, SimXmlNode& n );
+    ~SimAuth();
+
+    // Process an AT command.  Returns false if not a call-related command.
+    bool command( const QString& cmd );
+
+signals:
+    // Send a response to a command.
+    void send( const QString& line );
+
+private:
+    // secret key, set during initialization (from XML)
+    QString _ki;
+
+    // operator variant algorithm configuration field
+    QString _opc;
+
+    // arbitrary session ID starting number
+    int _session_start;
+
+    // parsed list of AID's
+    QStringList _aid_list;
+
+    // map of logical channel integers to AID's
+    QMap<int, QString> _logical_channels;
+
+    // run COMP128v1 algorithm against 'rand' and 'ki'
+    void gsmAuthenticate( QString rand, QString &sres, QString &kc );
+
+    // run Milenage algorithm with ki, rand, and autn
+    enum UmtsStatus umtsAuthenticate( QString rand, QString autn,
+            QString &res, QString &ck, QString &ik, QString &auts);
+
+    // open an AID logical channel
+    int openChannel( QString aid );
+
+    // close an AID logical channel
+    void closeChannel( int session_id );
+
+    // find the AID from a given session ID
+    bool getAidFromSession( int session_id, QString& aid );
+
+    // checks that the AID supports the given command
+    enum CmdType checkCommand( QString command, QString aid );
+
+    // returns the type of AID (USIM/ISIM/UNKNOWN)
+    enum AidType getAidType( QString aid );
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/5] simauth: Added SimAuth class for GSM/UMTS auth
  2017-10-03 16:32 [PATCH 1/5] comp128: GSM algorithm (comp128) implementation James Prestwood
  2017-10-03 16:32 ` [PATCH 2/5] aes: small module for AES128 James Prestwood
  2017-10-03 16:32 ` [PATCH 3/5] simauth: Added SimAuth class for GSM/UMTS authentication James Prestwood
@ 2017-10-03 16:32 ` James Prestwood
  2017-10-03 16:32 ` [PATCH 4/5] make: add simauth/aes/comp128 to build James Prestwood
  3 siblings, 0 replies; 7+ messages in thread
From: James Prestwood @ 2017-10-03 16:32 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 15429 bytes --]

SimAuth class is used to parse/respond to several AT commands. In
order to simulate running a SIMs GSM/UMTS authentication algorithms.

The class is initialized if the XML contains a "simauth" tag, which should
contain the secret key "ki" value, "opc" and a list of "aid" tags.

Implemented AT commands:

AT+CUAD: List available SIM applications (USIM or ISIM)
AT+CCHO: Open logical channel
AT+CGLA: Run either GSM/UMTS algorithm
AT+CCHC: Close logical channel

The GSM algorithm uses COMP128v1 (src/comp128.c), which generates
SRES and KC.

The UMTS algorithm uses the "Milenage" algorithm which generates
RES, CK and IK, or AUTS in case of sync failure.
---
 src/simauth.cpp | 414 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/simauth.h   | 105 ++++++++++++++
 2 files changed, 519 insertions(+)
 create mode 100644 src/simauth.cpp
 create mode 100644 src/simauth.h

diff --git a/src/simauth.cpp b/src/simauth.cpp
new file mode 100644
index 0000000..ce8263d
--- /dev/null
+++ b/src/simauth.cpp
@@ -0,0 +1,414 @@
+/****************************************************************************
+**
+** This file is part of the Qt Extended Opensource Package.
+**
+** Copyright (C) 2017  Intel Corporation. All rights reserved.
+**
+** This file may be used under the terms of the GNU General Public License
+** version 2.0 as published by the Free Software Foundation and appearing
+** in the file LICENSE.GPL included in the packaging of this file.
+**
+** Please review the following information to ensure GNU General Public
+** Licensing requirements will be met:
+**     http://www.fsf.org/licensing/licenses/info/GPLv2.html.
+**
+**
+****************************************************************************/
+
+#include "simauth.h"
+#include <qatutils.h>
+#include <qsimcontrolevent.h>
+
+extern "C" {
+#include "comp128.h"
+#include "aes.h"
+}
+
+#define QSTRING_TO_BUF(s) \
+    (uint8_t *)QByteArray::fromHex( s.toUtf8().data() ).data()
+
+SimAuth::SimAuth( QObject *parent, SimXmlNode& n )
+    : QObject( parent )
+{
+    SimXmlNode *child = n.children;
+
+    _ki = n.getAttribute( "ki" );
+    _opc = n.getAttribute( "opc" );
+    _session_start = 257;
+
+    _aid_list = QStringList();
+
+    // parse list of <aid> </aid>
+    while (child) {
+        if ( child->tag == "aid" )
+            _aid_list += QStringList( child->contents );
+
+        child = child->next;
+    }
+}
+
+SimAuth::~SimAuth()
+{
+}
+
+bool SimAuth::command( const QString& cmd )
+{
+    if ( cmd.startsWith( "AT+CUAD") ) {
+        QString response( "+CUAD: " );
+
+        if ( cmd.contains("=?") ) {
+            emit send( "OK" );
+            return true;
+        }
+
+        foreach ( const QString &str, _aid_list )
+            response += str;
+
+        response.append( "\n\nOK" );
+
+        emit send( response );
+    } else if ( cmd.startsWith( "AT+CCHO" ) ) {
+        QString aid;
+        int session_id = -1;
+
+        if ( !cmd.contains("=") ) {
+            emit send( "ERROR" );
+            return true;
+        }
+
+        if ( cmd.contains("=?") ) {
+            emit send( "OK" );
+            return true;
+        }
+
+        aid = cmd.split('=')[1];
+        aid = aid.replace("\"", "");
+
+        foreach ( const QString &str, _aid_list ) {
+            if ( str.contains( aid ) ) {
+                session_id = openChannel( aid );
+                break;
+            }
+        }
+
+        if ( session_id == -1 ) {
+            emit send( "ERROR" );
+            return true;
+        }
+
+        emit send( QString( "+CCHO: %1\n\nOK" ).arg(session_id, 0, 10) );
+    } else if ( cmd.startsWith( "AT+CGLA" ) ) {
+        QString aid;
+        QString data;
+        QString command;
+        QString parameters;
+        QString response;
+        enum CmdType type;
+        int session_id = -1;
+
+        if ( !cmd.contains("=") ) {
+            emit send( "ERROR" );
+            return true;
+        }
+
+        if ( cmd.contains("=?") ) {
+            emit send( "OK" );
+            return true;
+        }
+
+        data = cmd.split('=')[1];
+        session_id = data.split(',')[0].toInt();
+
+        if (!getAidFromSession( session_id, aid )) {
+            emit send( "ERROR" );
+            return true;
+        }
+
+        data = data.split(',')[2].replace("\"", "");
+        parameters = data.mid(10);
+
+        type = checkCommand( data, aid );
+
+        if (type == CMD_TYPE_GSM_AUTH) {
+            QString sres, kc;
+            QString rand = parameters.mid(2, 32);
+
+            gsmAuthenticate( rand, sres, kc );
+
+            response = QString( "+CGLA: 32,\"04 %1 08 %2 \"\n\nOK" )
+                    .arg( sres, kc );
+            response.replace( " ", "");
+
+        } else if (type == CMD_TYPE_UMTS_AUTH) {
+            enum UmtsStatus status;
+            QString res, ck, ik, auts;
+            QString rand = parameters.mid(2, 32);
+            QString autn = parameters.mid(36, 32);
+
+            status = umtsAuthenticate( rand, autn, res, ck, ik, auts );
+
+            response = QString("+CGLA: ");
+
+            QString test;
+
+            switch (status) {
+            case UMTS_OK:
+                response += QString( "88,\"DB08 %1 10 %2 10 %3\"\n\nOK" )
+                        .arg( res, ck, ik );
+                response.replace( " ", "" );
+
+                break;
+            case UMTS_INVALID_MAC:
+                response += QString( "4,\"%1\"\n\nOK")
+                        .arg( CMD_TYPE_APP_ERROR, 0, 16 );
+
+                break;
+            case UMTS_SYNC_FAILURE:
+                response == QString( "34,\"DC10 %1 \"\n\nOK" ).arg( auts );
+                response.replace( " ", "" );
+
+                break;
+            case UMTS_ERROR:
+                response = QString( "ERROR" );
+
+                break;
+            }
+        } else {
+            response = QString("+CGLA: 4,\"%1\"\n\nOK").arg(type, 0, 16);
+        }
+
+        emit send( response );
+    } else if ( cmd.startsWith( "AT+CCHC" ) ) {
+        int session_id = -1;
+
+        if ( !cmd.contains("=") ) {
+            emit send( "ERROR" );
+            return true;
+        }
+
+        if ( cmd.contains("=?") ) {
+            emit send( "OK" );
+            return true;
+        }
+
+        session_id = cmd.split('=')[1].toInt();
+
+        closeChannel(session_id);
+
+        emit send( "OK" );
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+int SimAuth::openChannel( QString aid )
+{
+    if ( _logical_channels.size() >= MAX_LOGICAL_CHANNELS )
+        return -1;
+
+    _logical_channels.insert( _session_start, aid );
+
+    return _session_start++;
+}
+
+void SimAuth::closeChannel( int session_id )
+{
+    _logical_channels.remove( session_id );
+}
+
+bool SimAuth::getAidFromSession( int session_id, QString& aid )
+{
+    if ( _logical_channels.contains( session_id ) ) {
+        aid = _logical_channels[session_id];
+        return true;
+    }
+
+    return false;
+}
+
+enum AidType SimAuth::getAidType( QString aid )
+{
+    if ( aid.mid(10, 4) == "1004" )
+        return AID_TYPE_ISIM;
+    else if ( aid.mid(10, 4) == "1002")
+        return AID_TYPE_USIM;
+
+    return AID_TYPE_UNKNOWN;
+}
+
+
+enum CmdType SimAuth::checkCommand( QString command, QString aid )
+{
+    QString cls = command.mid(0, 2);
+    QString ins = command.mid(2, 2);
+    QString p1 = command.mid(4, 2);
+    QString p2 = command.mid(6, 2);
+    QString lc = command.mid(8, 2);
+    AidType type = getAidType( aid );
+
+    if ( cls != "00" )
+        return CMD_TYPE_UNSUPPORTED_CLS;
+
+    if ( ins != "88" )
+        return CMD_TYPE_UNSUPPORTED_INS;
+
+    if ( p1 != "00" )
+        return CMD_TYPE_INCORRECT_P2_P1;
+
+    if ( p2 == "80" ) {
+        if ( lc != "11" )
+            return CMD_TYPE_WRONG_LENGTH;
+
+        if ( !(type == AID_TYPE_USIM || type == AID_TYPE_ISIM) )
+            return CMD_TYPE_APP_ERROR;
+
+        return CMD_TYPE_GSM_AUTH;
+    } else if ( p2 == "81" ) {
+        if ( lc != "22" )
+            return CMD_TYPE_WRONG_LENGTH;
+
+        if ( type != AID_TYPE_ISIM )
+            return CMD_TYPE_APP_ERROR;
+
+        return CMD_TYPE_UMTS_AUTH;
+    } else {
+        return CMD_TYPE_UNKNOWN;
+    }
+}
+
+void SimAuth::gsmAuthenticate( QString rand, QString &sres,
+        QString &kc )
+{
+    uint8_t *ki = QSTRING_TO_BUF( _ki );
+    uint8_t *_rand = QSTRING_TO_BUF( rand );
+    uint8_t _sres[4];
+    uint8_t _kc[8];
+
+    comp128( ki, _rand, _sres, _kc );
+
+    sres = QByteArray( (const char *)_sres, 4 ).toHex();
+    kc = QByteArray( (const char *)_kc, 8 ).toHex();
+}
+
+/*
+ * Helper to XOR an array
+ * to - result of XOR array
+ * a - array 1
+ * b - array 2
+ * len - size of aray
+ */
+#define XOR(to, a, b, len) \
+    for (i = 0; i < len; i++) { \
+        to[i] = a[i] ^ b[i]; \
+    }
+
+enum UmtsStatus SimAuth::umtsAuthenticate( QString rand, QString autn,
+        QString &res, QString &ck, QString &ik, QString &auts )
+{
+    int i;
+
+    uint8_t *ki = QSTRING_TO_BUF( _ki );
+    uint8_t *_rand = QSTRING_TO_BUF( rand );
+    uint8_t *_autn = QSTRING_TO_BUF( autn );
+    uint8_t *opc = QSTRING_TO_BUF( _opc );
+
+    uint8_t ak[6];
+    uint8_t sqn[6];
+    uint8_t amf[2];
+    uint8_t mac[8];
+    uint8_t _res[8];
+    uint8_t _ck[16];
+    uint8_t _ik[16];
+
+    uint8_t temp[16];
+    uint8_t out1[16];
+    uint8_t out2[16];
+    uint8_t in1[16];
+    uint8_t tmp1[16];
+    uint8_t tmp2[16];
+
+    // copy out AMF/MAC from AUTN
+    memcpy(amf, _autn + 6, 2);
+    memcpy(mac, _autn + 8, 8);
+
+    // TEMP = AES[RAND ^ OPc]
+    XOR(temp, _rand, opc, 16);
+    aes_encrypt(ki, 16, temp, temp, 16);
+
+    // f2 algorithm
+    // OUT2 == AES[(TEMP ^ OPc) ^ c2] ^ OPc]
+    XOR(tmp1, temp, opc, 16);
+    tmp1[15] ^= 1;
+    aes_encrypt(ki, 16, tmp1, tmp1, 16);
+    XOR(out2, tmp1, opc, 16);
+
+    // AK is first 6 bytes of OUT2
+    memcpy(ak, out2, 6);
+    // RES is last 8 bytes of OUT2
+    memcpy(_res, out2 + 8, 8);
+
+    // get SQN, first 6 bytes of AUTN are SQN^AK, so (SQN^AK)^AK = SQN
+    XOR(sqn, _autn, ak, 6);
+
+    // f1 algorithm
+    // setup IN1
+    memcpy(in1, sqn, 6);
+    memcpy(in1 + 6, amf, 2);
+    memcpy(in1 + 8, sqn, 6);
+    memcpy(in1 + 14, amf, 2);
+
+    for (i = 0; i < 16; i++)
+        tmp1[(i + 8) % 16] = in1[i] ^ opc[i];
+
+    /* tmp2 = TEMP ^ tmp1 */
+    XOR(tmp2, temp, tmp1, 16);
+    /* tmp2 = E[tmp2]k */
+    aes_encrypt(ki, 16, tmp2, tmp1, 16);
+    /* out1 = OUT1 = tmp1 ^ opc */
+    XOR(out1, tmp1, opc, 16);
+
+    if (memcmp(_autn + 8, out1, 8)) {
+        // f5* algorithm
+        // rot(TEMP ^ OPC, r5)
+        for (i = 0; i < 16; i++)
+            tmp1[(i + 4) % 16] = temp[i] ^ opc[i];
+
+        // XOR with c5
+        tmp1[15] ^= 1 << 3;
+        aes_encrypt(ki, 16, tmp1, tmp1, 16);
+        // XOR with OPc
+        XOR(tmp1, opc, tmp1, 16);
+
+        auts = QByteArray( (const char *)tmp1, 16 ).toHex();
+
+        return UMTS_INVALID_MAC;
+    }
+
+    // f3 algorithm
+    for (i = 0; i < 16; i++)
+        tmp1[(i + 12) % 16] = temp[i] ^ opc[i];
+
+    /* tmp1 ^ c3. c3 at bit 126 == 1 */
+    tmp1[15] ^= 1 << 1;
+    aes_encrypt(ki, 16, tmp1, _ck, 16);
+    /* ck ^ opc */
+    XOR(_ck, _ck, opc, 16);
+
+    // f4 algorithm
+    for (i = 0; i < 16; i++)
+        tmp1[(i + 8) % 16] = temp[i] ^ opc[i];
+
+    /* tmp1 ^ c4. c4@bit 125 == 1 */
+    tmp1[15] ^= 1 << 2;
+    aes_encrypt(ki, 16, tmp1, _ik, 16);
+    /* ik ^ opc */
+    XOR(_ik, _ik, opc, 16);
+
+    res = QByteArray( (const char *)_res, 8 ).toHex();
+    ck = QByteArray( (const char *)_ck, 16 ).toHex();
+    ik = QByteArray( (const char *)_ik, 16 ).toHex();
+
+    return UMTS_OK;
+}
diff --git a/src/simauth.h b/src/simauth.h
new file mode 100644
index 0000000..eb733f6
--- /dev/null
+++ b/src/simauth.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** This file is part of the Qt Extended Opensource Package.
+**
+** Copyright (C) 2017  Intel Corporation. All rights reserved.
+**
+** This file may be used under the terms of the GNU General Public License
+** version 2.0 as published by the Free Software Foundation and appearing
+** in the file LICENSE.GPL included in the packaging of this file.
+**
+** Please review the following information to ensure GNU General Public
+** Licensing requirements will be met:
+**     http://www.fsf.org/licensing/licenses/info/GPLv2.html.
+**
+**
+****************************************************************************/
+
+#ifndef SIMAUTH_H
+#define SIMAUTH_H
+
+#include "phonesim.h"
+
+#define MAX_LOGICAL_CHANNELS    4
+
+enum AidType {
+    AID_TYPE_USIM,
+    AID_TYPE_ISIM,
+    AID_TYPE_UNKNOWN
+};
+
+/*
+ * Some common errors
+ */
+enum CmdType {
+    CMD_TYPE_GSM_AUTH = 0,
+    CMD_TYPE_UMTS_AUTH = 1,
+    CMD_TYPE_UNSUPPORTED_CLS = 0x6E00,
+    CMD_TYPE_UNSUPPORTED_INS = 0x6D00,
+    CMD_TYPE_INCORRECT_P2_P1 = 0x6A86,
+    CMD_TYPE_WRONG_LENGTH = 0x6700,
+    CMD_TYPE_APP_ERROR = 0x9862,
+    CMD_TYPE_UNKNOWN = 0xFFFF
+};
+
+enum UmtsStatus {
+    UMTS_OK,            // Success
+    UMTS_INVALID_MAC,   // MAC did not match AUTN parameter
+    UMTS_SYNC_FAILURE,  // SQN did not match
+    UMTS_ERROR          // Any other error
+};
+
+class SimAuth : public QObject
+{
+    Q_OBJECT
+public:
+    SimAuth( QObject *parent, SimXmlNode& n );
+    ~SimAuth();
+
+    // Process an AT command.  Returns false if not a call-related command.
+    bool command( const QString& cmd );
+
+signals:
+    // Send a response to a command.
+    void send( const QString& line );
+
+private:
+    // secret key, set during initialization (from XML)
+    QString _ki;
+
+    // operator variant algorithm configuration field
+    QString _opc;
+
+    // arbitrary session ID starting number
+    int _session_start;
+
+    // parsed list of AID's
+    QStringList _aid_list;
+
+    // map of logical channel integers to AID's
+    QMap<int, QString> _logical_channels;
+
+    // run COMP128v1 algorithm against 'rand' and 'ki'
+    void gsmAuthenticate( QString rand, QString &sres, QString &kc );
+
+    // run Milenage algorithm with ki, rand, and autn
+    enum UmtsStatus umtsAuthenticate( QString rand, QString autn,
+            QString &res, QString &ck, QString &ik, QString &auts);
+
+    // open an AID logical channel
+    int openChannel( QString aid );
+
+    // close an AID logical channel
+    void closeChannel( int session_id );
+
+    // find the AID from a given session ID
+    bool getAidFromSession( int session_id, QString& aid );
+
+    // checks that the AID supports the given command
+    enum CmdType checkCommand( QString command, QString aid );
+
+    // returns the type of AID (USIM/ISIM/UNKNOWN)
+    enum AidType getAidType( QString aid );
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/5] make: add simauth/aes/comp128 to build
  2017-10-03 16:32 [PATCH 1/5] comp128: GSM algorithm (comp128) implementation James Prestwood
                   ` (2 preceding siblings ...)
  2017-10-03 16:32 ` [PATCH 3/5] simauth: Added SimAuth class for GSM/UMTS auth James Prestwood
@ 2017-10-03 16:32 ` James Prestwood
  2017-10-03 16:34   ` James Prestwood
  3 siblings, 1 reply; 7+ messages in thread
From: James Prestwood @ 2017-10-03 16:32 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1176 bytes --]

---
 Makefile.am  | 4 ++++
 configure.ac | 1 +
 2 files changed, 5 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 8d12c46..7feceba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,6 +16,9 @@ src_phonesim_SOURCES = src/main.cpp \
 			src/qsmsmessage.h src/qsmsmessage.cpp \
 			src/qcbsmessage.h src/qcbsmessage.cpp \
 			src/callmanager.h src/callmanager.cpp \
+			src/simauth.h src/simauth.cpp \
+			src/comp128.h src/comp128.c \
+			src/aes.h src/aes.c \
 			src/simfilesystem.h src/simfilesystem.cpp \
 			src/simapplication.h src/simapplication.cpp \
 			src/qgsmcodec.h src/qgsmcodec.cpp \
@@ -34,6 +37,7 @@ nodist_src_phonesim_SOURCES = src/ui_controlbase.h \
 				src/moc_phonesim.cpp \
 				src/moc_hardwaremanipulator.cpp \
 				src/moc_callmanager.cpp \
+				src/moc_simauth.cpp \
 				src/moc_simfilesystem.cpp \
 				src/moc_simapplication.cpp \
 				src/moc_qwsppdu.cpp
diff --git a/configure.ac b/configure.ac
index fb3c3a7..e97c573 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11,6 +11,7 @@ AC_PREFIX_DEFAULT(/usr/local)
 
 PKG_PROG_PKG_CONFIG
 
+AC_PROG_CC
 AC_PROG_CXX
 AC_PROG_INSTALL
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 4/5] make: add simauth/aes/comp128 to build
  2017-10-03 16:32 ` [PATCH 4/5] make: add simauth/aes/comp128 to build James Prestwood
@ 2017-10-03 16:34   ` James Prestwood
  0 siblings, 0 replies; 7+ messages in thread
From: James Prestwood @ 2017-10-03 16:34 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1443 bytes --]

Please disregard these 5 latest patches. A fixup patch made it into my 
patch directory. Sorry about that.

Thanks,

James


On 10/03/2017 09:32 AM, James Prestwood wrote:
> ---
>   Makefile.am  | 4 ++++
>   configure.ac | 1 +
>   2 files changed, 5 insertions(+)
>
> diff --git a/Makefile.am b/Makefile.am
> index 8d12c46..7feceba 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -16,6 +16,9 @@ src_phonesim_SOURCES = src/main.cpp \
>   			src/qsmsmessage.h src/qsmsmessage.cpp \
>   			src/qcbsmessage.h src/qcbsmessage.cpp \
>   			src/callmanager.h src/callmanager.cpp \
> +			src/simauth.h src/simauth.cpp \
> +			src/comp128.h src/comp128.c \
> +			src/aes.h src/aes.c \
>   			src/simfilesystem.h src/simfilesystem.cpp \
>   			src/simapplication.h src/simapplication.cpp \
>   			src/qgsmcodec.h src/qgsmcodec.cpp \
> @@ -34,6 +37,7 @@ nodist_src_phonesim_SOURCES = src/ui_controlbase.h \
>   				src/moc_phonesim.cpp \
>   				src/moc_hardwaremanipulator.cpp \
>   				src/moc_callmanager.cpp \
> +				src/moc_simauth.cpp \
>   				src/moc_simfilesystem.cpp \
>   				src/moc_simapplication.cpp \
>   				src/moc_qwsppdu.cpp
> diff --git a/configure.ac b/configure.ac
> index fb3c3a7..e97c573 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -11,6 +11,7 @@ AC_PREFIX_DEFAULT(/usr/local)
>   
>   PKG_PROG_PKG_CONFIG
>   
> +AC_PROG_CC
>   AC_PROG_CXX
>   AC_PROG_INSTALL
>   


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 4/5] make: add simauth/aes/comp128 to build
  2017-10-03 16:35 [PATCH 1/5] comp128: GSM algorithm (comp128) implementation James Prestwood
@ 2017-10-03 16:35 ` James Prestwood
  0 siblings, 0 replies; 7+ messages in thread
From: James Prestwood @ 2017-10-03 16:35 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1176 bytes --]

---
 Makefile.am  | 4 ++++
 configure.ac | 1 +
 2 files changed, 5 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 8d12c46..7feceba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,6 +16,9 @@ src_phonesim_SOURCES = src/main.cpp \
 			src/qsmsmessage.h src/qsmsmessage.cpp \
 			src/qcbsmessage.h src/qcbsmessage.cpp \
 			src/callmanager.h src/callmanager.cpp \
+			src/simauth.h src/simauth.cpp \
+			src/comp128.h src/comp128.c \
+			src/aes.h src/aes.c \
 			src/simfilesystem.h src/simfilesystem.cpp \
 			src/simapplication.h src/simapplication.cpp \
 			src/qgsmcodec.h src/qgsmcodec.cpp \
@@ -34,6 +37,7 @@ nodist_src_phonesim_SOURCES = src/ui_controlbase.h \
 				src/moc_phonesim.cpp \
 				src/moc_hardwaremanipulator.cpp \
 				src/moc_callmanager.cpp \
+				src/moc_simauth.cpp \
 				src/moc_simfilesystem.cpp \
 				src/moc_simapplication.cpp \
 				src/moc_qwsppdu.cpp
diff --git a/configure.ac b/configure.ac
index fb3c3a7..e97c573 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11,6 +11,7 @@ AC_PREFIX_DEFAULT(/usr/local)
 
 PKG_PROG_PKG_CONFIG
 
+AC_PROG_CC
 AC_PROG_CXX
 AC_PROG_INSTALL
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-10-03 16:35 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-10-03 16:32 [PATCH 1/5] comp128: GSM algorithm (comp128) implementation James Prestwood
2017-10-03 16:32 ` [PATCH 2/5] aes: small module for AES128 James Prestwood
2017-10-03 16:32 ` [PATCH 3/5] simauth: Added SimAuth class for GSM/UMTS authentication James Prestwood
2017-10-03 16:32 ` [PATCH 3/5] simauth: Added SimAuth class for GSM/UMTS auth James Prestwood
2017-10-03 16:32 ` [PATCH 4/5] make: add simauth/aes/comp128 to build James Prestwood
2017-10-03 16:34   ` James Prestwood
  -- strict thread matches above, loose matches on Subject: below --
2017-10-03 16:35 [PATCH 1/5] comp128: GSM algorithm (comp128) implementation James Prestwood
2017-10-03 16:35 ` [PATCH 4/5] make: add simauth/aes/comp128 to build James Prestwood

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.