libosmogsm: Factor out the C2 derivation function

3GPP specifies the C2 derivation function (generating GSM SRES from UMTS XRES)
independent of the MILENAGE algorithm.  So instead of open-coding it in
milenage.c:gsm_milenage(), let's create a separate public function
osmo_auth_c2() similar to the already-existing osmo_auth_c3() function.

gsm_milenage() can then simply use that function.

Change-Id: I0e7cd55f5578f891cb6cc1b0442920ba5beddae4
diff --git a/src/gsm/auth_core.c b/src/gsm/auth_core.c
index 2b6f35a..ad5967d 100644
--- a/src/gsm/auth_core.c
+++ b/src/gsm/auth_core.c
@@ -363,4 +363,33 @@
 		kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
 }
 
+/*! Derive GSM SRES from UMTS [X]RES (auth function c2 from 3GPP TS 33.103 Section 6.8.1.2
+ *  \param[out] sres GSM SRES value, 4 byte target buffer
+ *  \param[in] res UMTS XRES, 4..16 bytes input buffer
+ *  \param[in] res_len length of res parameter (in bytes)
+ *  \param[in] sres_deriv_func SRES derivation function (1 or 2, see 3GPP TS 55.205 Section 4
+ */
+void osmo_auth_c2(uint8_t sres[4], const uint8_t *res, size_t res_len, uint8_t sres_deriv_func)
+{
+	uint8_t xres[16];
+
+	OSMO_ASSERT(sres_deriv_func == 1 || sres_deriv_func == 2);
+	OSMO_ASSERT(res_len <= sizeof(xres));
+
+	memcpy(xres, res, res_len);
+
+	/* zero-pad the end, if XRES is < 16 bytes */
+	if (res_len < sizeof(xres))
+		memset(xres+res_len, 0, sizeof(xres)-res_len);
+
+	if (sres_deriv_func == 1) {
+		/* SRES derivation function #1 */
+		for (unsigned int i = 0; i < 4; i++)
+			sres[i] = xres[i] ^ xres[4+i] ^ xres[8+i] ^ xres[12+i];
+	} else {
+		/* SRES derivation function #2 */
+		memcpy(sres, xres, 4);
+	}
+}
+
 /*! @} */