summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/gsm/a5.h14
-rw-r--r--src/gsm/a5.c68
2 files changed, 82 insertions, 0 deletions
diff --git a/include/osmocom/gsm/a5.h b/include/osmocom/gsm/a5.h
index 55ce24dc..7e6a17c4 100644
--- a/include/osmocom/gsm/a5.h
+++ b/include/osmocom/gsm/a5.h
@@ -27,6 +27,18 @@
#include <osmocom/core/bits.h>
+/*! \defgroup a5 GSM A5 ciphering algorithm
+ * @{
+ */
+
+/*! \file gsm/a5.h
+ * \brief Osmocom GSM A5 ciphering algorithm header
+ */
+
+/*! \brief Converts a frame number into the 22 bit number used in A5/x
+ * \param[in] fn The true framenumber
+ * \return 22 bit word
+ */
static inline uint32_t
osmo_a5_fn_count(uint32_t fn)
{
@@ -46,4 +58,6 @@ void osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul);
void osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul);
void osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul);
+/*! }@ */
+
#endif /* __OSMO_A5_H__ */
diff --git a/src/gsm/a5.c b/src/gsm/a5.c
index 31c2ba95..36978c48 100644
--- a/src/gsm/a5.c
+++ b/src/gsm/a5.c
@@ -26,10 +26,28 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+/*! \addtogroup a5
+ * @{
+ */
+
+/*! \file gsm/a5.c
+ * \brief Osmocom GSM A5 ciphering algorithm implementation
+ */
+
#include <string.h>
#include <osmocom/gsm/a5.h>
+/*! \brief Main method to generate a A5/x cipher stream
+ * \param[in] n Which A5/x method to use
+ * \param[in] key 8 byte array for the key (as received from the SIM)
+ * \param[in] fn Frame number
+ * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
+ * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
+ *
+ * Currently A5/[0-2] are supported.
+ * Either (or both) of dl/ul can be NULL if not needed.
+ */
void
osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
{
@@ -76,6 +94,10 @@ osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
#define A5_R3_TAPS 0x700080 /* x^23 + x^15 + x^2 + x + 1 */
#define A5_R4_TAPS 0x010800 /* x^17 + x^5 + 1 */
+/*! \brief Computes parity of a 32-bit word
+ * \param[in] x 32 bit word
+ * \return Parity bit (xor of all bits) as 0 or 1
+ */
static inline uint32_t
_a5_12_parity(uint32_t x)
{
@@ -87,12 +109,24 @@ _a5_12_parity(uint32_t x)
return x & 1;
}
+/*! \brief Compute majority bit from 3 taps
+ * \param[in] v1 LFSR state ANDed with tap-bit
+ * \param[in] v2 LFSR state ANDed with tap-bit
+ * \param[in] v3 LFSR state ANDed with tap-bit
+ * \return The majority bit (0 or 1)
+ */
static inline uint32_t
_a5_12_majority(uint32_t v1, uint32_t v2, uint32_t v3)
{
return (!!v1 + !!v2 + !!v3) >= 2;
}
+/*! \brief Compute the next LFSR state
+ * \param[in] r Current state
+ * \param[in] mask LFSR mask
+ * \param[in] taps LFSR taps
+ * \return Next state
+ */
static inline uint32_t
_a5_12_clock(uint32_t r, uint32_t mask, uint32_t taps)
{
@@ -108,6 +142,10 @@ _a5_12_clock(uint32_t r, uint32_t mask, uint32_t taps)
#define A51_R2_CLKBIT 0x000400
#define A51_R3_CLKBIT 0x000400
+/*! \brief GSM A5/1 Clocking function
+ * \param[in] r Register state
+ * \param[in] force Non-zero value disable conditional clocking
+ */
static inline void
_a5_1_clock(uint32_t r[], int force)
{
@@ -129,6 +167,10 @@ _a5_1_clock(uint32_t r[], int force)
r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
}
+/*! \brief GSM A5/1 Output function
+ * \param[in] r Register state
+ * \return The A5/1 output function bit
+ */
static inline uint8_t
_a5_1_get_output(uint32_t r[])
{
@@ -137,6 +179,14 @@ _a5_1_get_output(uint32_t r[])
(r[2] >> (A5_R3_LEN-1));
}
+/*! \brief Generate a GSM A5/1 cipher stream
+ * \param[in] key 8 byte array for the key (as received from the SIM)
+ * \param[in] fn Frame number
+ * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
+ * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
+ *
+ * Either (or both) of dl/ul can be NULL if not needed.
+ */
void
osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
{
@@ -200,6 +250,10 @@ osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
#define A52_R4_CLKBIT1 0x000008
#define A52_R4_CLKBIT2 0x000080
+/*! \brief GSM A5/2 Clocking function
+ * \param[in] r Register state
+ * \param[in] force Non-zero value disable conditional clocking
+ */
static inline void
_a5_2_clock(uint32_t r[], int force)
{
@@ -223,6 +277,10 @@ _a5_2_clock(uint32_t r[], int force)
r[3] = _a5_12_clock(r[3], A5_R4_MASK, A5_R4_TAPS);
}
+/*! \brief GSM A5/2 Output function
+ * \param[in] r Register state
+ * \return The A5/2 output function bit
+ */
static inline uint8_t
_a5_2_get_output(uint32_t r[])
{
@@ -238,6 +296,14 @@ _a5_2_get_output(uint32_t r[])
return b;
}
+/*! \brief Generate a GSM A5/1 cipher stream
+ * \param[in] key 8 byte array for the key (as received from the SIM)
+ * \param[in] fn Frame number
+ * \param[out] dl Pointer to array of ubits to return Downlink cipher stream
+ * \param[out] ul Pointer to array of ubits to return Uplink cipher stream
+ *
+ * Either (or both) of dl/ul can be NULL if not needed.
+ */
void
osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
{
@@ -298,3 +364,5 @@ osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
ul[i] = _a5_2_get_output(r);
}
}
+
+/*! }@ */