/// <summary> /// 该方法先判断输入的nas信令是否加密,如果没有加密,则直接调用明文解析方法plain()进行解析; /// 否则先进行解密,再进行明文解析 /// </summary> /// <param name="nas_pdu">nas信令编码</param> /// <param name="direction">该nas信令所在的s1ap信令的方向</param> /// <param name="Kasme_1">从diameter信令中获得的Kasme list</param> public void decrypt(byte[] nas_pdu, byte direction, List <byte[]> Kasme_1) { // 清空数据 cause_str = ""; byte proDiscriminator = 0, EBI = 0; byte headType = 0; byte sqn = 0; byte header = 0; bool ciper_or = false; byte down_sqn = 0, up_sqn = 0; uint count = 0; List <byte[]> Kasme1 = new List <byte[]>(); byte[] Kasme = new byte[32]; byte[] Knas1 = new byte[32]; byte[] Knas = new byte[16]; proDiscriminator = (byte)(nas_pdu[0] & 0x0f); //指示nas信令类型是ESM or EMM if (proDiscriminator == 0x07) //EMM 消息 { headType = (byte)((nas_pdu[0] & 0xf0) >> 4); } else if (proDiscriminator == 0x02) //ESM消息 { EBI = (byte)((nas_pdu[0] & 0xf0) >> 4); //EPS bear identity } //用于判断security header Type=2,4时,加密开关是否关闭,若关闭,则不需要进行解密。 if ((headType == 1) || (headType == 2) || (headType == 3) || (headType == 4)) //当headerType=1,2,3,4时才有nasPlain,sqn,header,ciper_or. { byte[] nasPlain = new byte[nas_pdu.Length - 6]; //nasPlain表示加密的nas部分,但是这只适宜于headertype=1,2,3,4的情况,不适于type=0. sqn = nas_pdu[5]; //获得每条信令的序列号(对于service request有特殊情况,该表达式不是其序列号,故需要单独处理) Array.Copy(nas_pdu, 6, nasPlain, 0, nasPlain.Length); //当nas不是plain message时(或者完整性保护,或者加密),去掉nas_pdu安全头部 //把剩余部分放在nasPlain中。 header = nasPlain[0]; //特征字节,指示nas信令是否属于nas esm 消息 ciper_or = field(header); //用于判断是否打开加密开关,如果是true,则加密开关关闭,不加密 if (headType == 1) //只进行完整性保护,不加密 { #region //用于计算加密所使用的参数COUNT if (direction == 0)//方向下行(MME->eNB) { down_sqn = sqn; if (System.Math.Abs(down_sqn - re_down_sqn) >= 128) { down_overflow++; } re_down_sqn = down_sqn; count = (uint)(down_overflow << 8 | down_sqn); //把溢出值与序列号拼接 } if (direction == 1) //方向上行(eNB->MME) { up_sqn = sqn; if (System.Math.Abs(up_sqn - re_up_sqn) >= 128) { down_overflow++; } re_up_sqn = up_sqn; count = (uint)(up_overflow << 8 | up_sqn); } cause_str = cause1.NasCause(nasPlain);//解析nas信令中的 cause IndexCause = cause1.Index; LengthCause = cause1.Length; plain(nasPlain); #endregion } else if (headType == 2)//完整性保护并加密(是否真的加密还需要判断加密开关是否打开) { #region if (direction == 0) { down_sqn = sqn; if (System.Math.Abs(down_sqn - re_down_sqn) >= 128) { down_overflow++; } re_down_sqn = down_sqn; count = (uint)(down_overflow << 8 | down_sqn);//把溢出值与序列号拼接 } if (direction == 1) { up_sqn = sqn; if (System.Math.Abs(up_sqn - re_up_sqn) >= 128) { down_overflow++; } re_up_sqn = up_sqn; count = (uint)(up_overflow << 8 | up_sqn); } if ((header == 0x07) || (ciper_or == true))//虽然安全头类型为2,但是加密开关关闭故不加密 { plain(nasPlain); IndexCause = cause1.Index; LengthCause = cause1.Length; } else { if (Kasme_1.Count > 0) //diameter信令分配有根密钥 { Kasme = Kasme_1[Kasme_i]; //在此处获得Kasme数组中合适的Kasme //解密模块,注意三种算法的IK是不同的 if (algorithm == 1) //加密算法选择EEA1,即snow 3G,下面的解密方法具体见EEA1和KDF算法的介绍 { #region UInt32[] IK1 = new UInt32[4];//存放解密所需的IK值(count,方向,identity组成) if (direction == 0) { IK1[0] = 0; IK1[1] = count; IK1[2] = 0; IK1[3] = count; } if (direction == 1) { IK1[0] = 0x04000000; IK1[1] = count; IK1[2] = 0x04000000; IK1[3] = count; } byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16); //获得Knas nasPlain = eea1.snow(nasPlain, Knas, IK1); //解析出明文 #endregion } else if (algorithm == 2)//加密算法选择EEA2,即AES,下面的解密方法具体见EEA2和KDF算法的介绍 { #region byte[] count1 = new byte[4]; count1 = uintToBytes(count); byte[] diret = new byte[4];//用于表示direction部分 byte[] IK = new byte[16]; //EEA2的IK与EEA1不同 if (direction == 0) { diret[0] = 0; diret[1] = 0; diret[2] = 0; diret[3] = 0; } if (direction == 1) { diret[0] = 0x04; diret[1] = 0; diret[2] = 0; diret[3] = 0; } Array.Copy(count1, 0, IK, 0, 4); Array.Copy(diret, 0, IK, 4, 4); byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x02, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16); //获得Knas nasPlain = eea2.aes(nasPlain, Knas, IK); //解析明文 #endregion } else if (algorithm == 3)//加密算法选择EEA2,即ZUC,下面的解密方法具体见EEA3和KDF算法的介绍 { #region byte[] count1 = new byte[4]; count1 = uintToBytes(count); byte[] diret = new byte[4];//用于表示direction部分 byte[] IK = new byte[32]; if (direction == 0) { diret[0] = 0; diret[1] = 0; diret[2] = 0; diret[3] = 0; } if (direction == 1) { diret[0] = 0x04; diret[1] = 0; diret[2] = 0; diret[3] = 0; } //注意三种算法的IK计算方法不同(程序中的算法有待实际验证) Array.Copy(diret, 0, IK, 0, 4); Array.Copy(count1, 0, IK, 4, 4); Array.Copy(diret, 0, IK, 8, 4); Array.Copy(count1, 0, IK, 12, 4); byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x03, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16);//获得Knas nasPlain = eea3.zuc(nasPlain, Knas, IK); #endregion } plain(nasPlain); IndexCause = cause1.Index; LengthCause = cause1.Length; cause_str = cause1.NasCause(nasPlain); } else//没有从S6a口获得密钥 { identity = ""; cause_str = ""; ue_ip = ""; EsmMessage = "ciperd message"; } } #endregion } else if (headType == 3)//只进行保证性保护 { #region down_sqn = 0; down_overflow = 0; count = (uint)(down_overflow << 8 | down_sqn); cause_str = cause1.NasCause(nasPlain); plain(nasPlain); IndexCause = cause1.Index; LengthCause = cause1.Length; #endregion } else if (headType == 4)//使用新的安全上下文中的KASME加密,故在这里需要更新加密密钥 { #region up_sqn = 0; up_overflow = 0; count = (uint)(up_overflow << 8 | up_sqn); if ((header == 0x07) || (ciper_or == true))//虽然安全头类型为4,但是不加密 { plain(nasPlain); cause_str = cause1.NasCause(nasPlain); IndexCause = cause1.Index; LengthCause = cause1.Length; } else //解密模块,注意三种算法的IK是不同的 { //只有需要解密时,才能更改或获得Kasme,因为即使headType==2,4也不一定会加密,也与加密开关有关系 Kasme_i++;//当headertype==4时,要更新Kasme if (Kasme_1.Count > 0) { Kasme = Kasme_1[Kasme_i];//在此处获得Kasme数组中合适的Kasme #region if (algorithm == 1) { #region UInt32[] IK1 = new UInt32[4];//存放解密所需的IK值(count,方向,identity组成) if (direction == 0) { IK1[0] = 0; IK1[1] = count; IK1[2] = 0; IK1[3] = count; } if (direction == 1) { IK1[0] = 0x04000000; IK1[1] = count; IK1[2] = 0x04000000; IK1[3] = count; } byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16); //获得Knas nasPlain = eea1.snow(nasPlain, Knas, IK1); //解析出明文 #endregion } else if (algorithm == 2) { #region byte[] count1 = new byte[4]; count1 = uintToBytes(count); byte[] diret = new byte[4];//用于表示direction部分 byte[] IK = new byte[16]; //EEA2的IK与EEA1不同 if (direction == 0) { diret[0] = 0; diret[1] = 0; diret[2] = 0; diret[3] = 0; } if (direction == 1) { diret[0] = 0x04; diret[1] = 0; diret[2] = 0; diret[3] = 0; } Array.Copy(count1, 0, IK, 0, 4); Array.Copy(diret, 0, IK, 4, 4); byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x02, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16); //获得Knas nasPlain = eea2.aes(nasPlain, Knas, IK); //解析明文 #endregion } else if (algorithm == 3) { #region byte[] count1 = new byte[4]; count1 = uintToBytes(count); byte[] diret = new byte[4];//用于表示direction部分 byte[] IK = new byte[32]; if (direction == 0) { diret[0] = 0; diret[1] = 0; diret[2] = 0; diret[3] = 0; } if (direction == 1) { diret[0] = 0x04; diret[1] = 0; diret[2] = 0; diret[3] = 0; } //注意三种算法的IK计算方法不同(程序中的算法有待实际验证) Array.Copy(diret, 0, IK, 0, 4); Array.Copy(count1, 0, IK, 4, 4); Array.Copy(diret, 0, IK, 8, 4); Array.Copy(count1, 0, IK, 12, 4); byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x03, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16);//获得Knas nasPlain = eea3.zuc(nasPlain, Knas, IK); #endregion } //decrypt2();//解密函数(密钥更新) #endregion plain(nasPlain); cause_str = cause1.NasCause(nasPlain); IndexCause = cause1.Index; LengthCause = cause1.Length; } else //没有从S6a口获得密钥 { identity = ""; cause_str = ""; ue_ip = ""; EsmMessage = "ciperd message"; } } #endregion } //因为此处还要包括安全头部的6字节 IndexEsm = IndexEsm + 6; IndexEmm = IndexEmm + 6; IndexCause = IndexCause + 6; IndexIP = IndexIP + 6; IndexIdentity = IndexIdentity + 6; } else if (headType == 0)//不加密,也不进行完整性保护 { plain(nas_pdu); cause_str = cause1.NasCause(nas_pdu); } else //此处表示其余的情况全部视为service request { #region sqn = (byte)(nas_pdu[1] & 0x1f);//service request 的序列号获取 if (direction == 0) { down_sqn = sqn; if (System.Math.Abs(down_sqn - re_down_sqn) >= 128) { down_overflow++; } re_down_sqn = down_sqn; count = (uint)(down_overflow << 8 | down_sqn);//把溢出值与序列号拼接 } if (direction == 1) { up_sqn = sqn; if (System.Math.Abs(up_sqn - re_up_sqn) >= 128) { down_overflow++; } re_up_sqn = up_sqn; count = (uint)(up_overflow << 8 | up_sqn); } IndexEsm = 0; LengthEmm = 1; EsmMessage = "service request"; esmType = 255;//由于service request既不是EMM消息也不是ESM消息,故没有其编号,暂定为255. #endregion } }
public void decrypt(byte[] nas_pdu, int direction, List <byte[]> kasme)//数组nas_pdu 是nas数据流 { cause_str = ""; byte proDiscriminator = 0, EBI = 0; byte headType1 = 0, headType = 0; byte sqn = 0; byte header = 0; bool ciper_or = false; byte down_sqn = 0, up_sqn = 0; uint count = 0; List <byte[]> Kasme1 = new List <byte[]>(); byte[] Kasme = new byte[32]; byte[] Knas1 = new byte[32]; byte[] Knas = new byte[16]; proDiscriminator = (byte)(nas_pdu[0] & 0x0f); if (proDiscriminator == 0x07) { headType1 = (byte)((nas_pdu[0] & 0xf0) >> 4); } else if (proDiscriminator == 0x02) { EBI = (byte)((nas_pdu[0] & 0xf0) >> 4); } //用于判断security header Type=2,4时,加密开关是否关闭,若关闭,则不需要进行解密。 if ((headType1 == 1) || (headType1 == 2) || (headType1 == 3) || (headType1 == 4)) //当headerType=1,2,3,4时才有nasPlain,sqn,header,ciper_or. { byte[] nasPlain = new byte[nas_pdu.Length - 6]; //nasPlain表示加密的nas部分,但是这只适宜于headertype=1,2,3,4的情况,不适于type=0. sqn = nas_pdu[5]; //获得每条信令的序列号(对于service request有特殊情况,该表达式不是其序列号,故需要单独处理) Array.Copy(nas_pdu, 6, nasPlain, 0, nasPlain.Length); header = nasPlain[0]; ciper_or = field(header); if (headType1 == 1) { #region if (direction == 0) { down_sqn = sqn; if (System.Math.Abs(down_sqn - re_down_sqn) >= 128) { down_overflow++; } re_down_sqn = down_sqn; count = (uint)(down_overflow << 8 | down_sqn);//把溢出值与序列号拼接 } if (direction == 1) { up_sqn = sqn; if (System.Math.Abs(up_sqn - re_up_sqn) >= 128) { down_overflow++; } re_up_sqn = up_sqn; count = (uint)(up_overflow << 8 | up_sqn); } cause_str = cause1.NasCause(nasPlain); plain(nasPlain); #endregion } else if (headType1 == 2) { #region if (direction == 0) { down_sqn = sqn; if (System.Math.Abs(down_sqn - re_down_sqn) >= 128) { down_overflow++; } re_down_sqn = down_sqn; count = (uint)(down_overflow << 8 | down_sqn);//把溢出值与序列号拼接 } if (direction == 1) { up_sqn = sqn; if (System.Math.Abs(up_sqn - re_up_sqn) >= 128) { down_overflow++; } re_up_sqn = up_sqn; count = (uint)(up_overflow << 8 | up_sqn); } if ((header == 0x07) || (ciper_or == true))//虽然安全头类型为2,但是不加密 { plain(nasPlain); } else { if (kasme.Count > 0) { //Kasme1 = convert(Kasme_1);//将string的Kasme转为byte数组 Kasme = kasme[MainForm.kasmeCount];//在此处获得Kasme数组中合适的Kasme //解密模块,注意三种算法的IK是不同的 if (algorithm == 1) { #region UInt32[] IK1 = new UInt32[4];//存放解密所需的IK值(count,方向,identity组成) if (direction == 0) { IK1[0] = 0; IK1[1] = count; IK1[2] = 0; IK1[3] = count; } if (direction == 1) { IK1[0] = 0x04000000; IK1[1] = count; IK1[2] = 0x04000000; IK1[3] = count; } byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16); //获得Knas nasPlain = eea1.snow(nasPlain, Knas, IK1); //解析出明文 #endregion } else if (algorithm == 2) { #region byte[] count1 = new byte[4]; count1 = uintToBytes(count); byte[] diret = new byte[4];//用于表示direction部分 byte[] IK = new byte[16]; //EEA2的IK与EEA1不同 if (direction == 0) { diret[0] = 0; diret[1] = 0; diret[2] = 0; diret[3] = 0; } if (direction == 1) { diret[0] = 0x04; diret[1] = 0; diret[2] = 0; diret[3] = 0; } Array.Copy(count1, 0, IK, 0, 4); Array.Copy(diret, 0, IK, 4, 4); byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x02, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16); //获得Knas nasPlain = eea2.aes(nasPlain, Knas, IK); //解析明文 #endregion } else if (algorithm == 3) { #region byte[] count1 = new byte[4]; count1 = uintToBytes(count); byte[] diret = new byte[4];//用于表示direction部分 byte[] IK = new byte[32]; if (direction == 0) { diret[0] = 0; diret[1] = 0; diret[2] = 0; diret[3] = 0; } if (direction == 1) { diret[0] = 0x04; diret[1] = 0; diret[2] = 0; diret[3] = 0; } //注意三种算法的IK计算方法不同(程序中的算法有待实际验证) Array.Copy(diret, 0, IK, 0, 4); Array.Copy(count1, 0, IK, 4, 4); Array.Copy(diret, 0, IK, 8, 4); Array.Copy(count1, 0, IK, 12, 4); byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x03, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16);//获得Knas nasPlain = eea3.zuc(nasPlain, Knas, IK); #endregion } plain(nasPlain); cause_str = cause1.NasCause(nasPlain); } else//没有获得密钥 { identity = ""; cause_str = ""; ue_ip = ""; str2 = "ciperd message"; } } #endregion } else if (headType1 == 3) { #region down_sqn = 0; down_overflow = 0; count = (uint)(down_overflow << 8 | down_sqn); cause_str = cause1.NasCause(nasPlain); plain(nasPlain); #endregion } else if (headType1 == 4) { #region up_sqn = 0; up_overflow = 0; count = (uint)(up_overflow << 8 | up_sqn); if ((header == 0x07) || (ciper_or == true))//虽然安全头类型为4,但是不加密 { plain(nasPlain); } else //解密模块,注意三种算法的IK是不同的 { //只有需要解密时,才能更改或获得Kasme,因为即使headType==2,4也不一定会加密,也与加密开关有关系 MainForm.kasmeCount++;//当headertype==4时,要更新Kasme if (kasme.Count > 0) { //Kasme1 = convert(Kasme_1);//将string的Kasme转为byte数组 Kasme = kasme[MainForm.kasmeCount];//在此处获得Kasme数组中合适的Kasme #region if (algorithm == 1) { #region UInt32[] IK1 = new UInt32[4];//存放解密所需的IK值(count,方向,identity组成) if (direction == 0) { IK1[0] = 0; IK1[1] = count; IK1[2] = 0; IK1[3] = count; } if (direction == 1) { IK1[0] = 0x04000000; IK1[1] = count; IK1[2] = 0x04000000; IK1[3] = count; } byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16); //获得Knas nasPlain = eea1.snow(nasPlain, Knas, IK1); //解析出明文 #endregion } else if (algorithm == 2) { #region byte[] count1 = new byte[4]; count1 = uintToBytes(count); byte[] diret = new byte[4];//用于表示direction部分 byte[] IK = new byte[16]; //EEA2的IK与EEA1不同 if (direction == 0) { diret[0] = 0; diret[1] = 0; diret[2] = 0; diret[3] = 0; } if (direction == 1) { diret[0] = 0x04; diret[1] = 0; diret[2] = 0; diret[3] = 0; } Array.Copy(count1, 0, IK, 0, 4); Array.Copy(diret, 0, IK, 4, 4); byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x02, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16); //获得Knas nasPlain = eea2.aes(nasPlain, Knas, IK); //解析明文 #endregion } else if (algorithm == 3) { #region byte[] count1 = new byte[4]; count1 = uintToBytes(count); byte[] diret = new byte[4];//用于表示direction部分 byte[] IK = new byte[32]; if (direction == 0) { diret[0] = 0; diret[1] = 0; diret[2] = 0; diret[3] = 0; } if (direction == 1) { diret[0] = 0x04; diret[1] = 0; diret[2] = 0; diret[3] = 0; } //注意三种算法的IK计算方法不同(程序中的算法有待实际验证) Array.Copy(diret, 0, IK, 0, 4); Array.Copy(count1, 0, IK, 4, 4); Array.Copy(diret, 0, IK, 8, 4); Array.Copy(count1, 0, IK, 12, 4); byte[] str = new byte[7] { 0x15, 0x01, 0x00, 0x01, 0x03, 0x00, 0x01 }; Knas1 = kdf.kdf_decode(Kasme, str); Array.Copy(Knas1, 16, Knas, 0, 16);//获得Knas nasPlain = eea3.zuc(nasPlain, Knas, IK); #endregion } //decrypt2();//解密函数(密钥更新) #endregion plain(nasPlain); cause_str = cause1.NasCause(nasPlain); } else //没有从S6a口获得密钥 { identity = ""; cause_str = ""; ue_ip = ""; str2 = "ciperd message"; } } #endregion } } else if (headType1 == 0) //不加密 { plain(nas_pdu); //注意函数中的参数是nas_pdu,与上面的nasPlain不同 cause_str = cause1.NasCause(nas_pdu); } else //此处表示其余的情况全部视为service request { #region sqn = (byte)(nas_pdu[1] & 0x1f);//service request 的序列号获取 if (direction == 0) { down_sqn = sqn; if (System.Math.Abs(down_sqn - re_down_sqn) >= 128) { down_overflow++; } re_down_sqn = down_sqn; count = (uint)(down_overflow << 8 | down_sqn);//把溢出值与序列号拼接 } if (direction == 1) { up_sqn = sqn; if (System.Math.Abs(up_sqn - re_up_sqn) >= 128) { down_overflow++; } re_up_sqn = up_sqn; count = (uint)(up_overflow << 8 | up_sqn); } str2 = "service request"; esmType = 255;//由于service request既不是EMM消息也不是ESM消息,故没有其编号,暂定为255. #endregion } }