├── .gitignore ├── .travis.yml ├── COPYING ├── ChangeLog ├── Makefile ├── README ├── a5.c ├── a5.h ├── a53.h ├── a53test.cpp ├── a5_speed.c ├── a5_test.c ├── a5_test.ok ├── bits.c ├── bits.h ├── debian ├── changelog ├── compat ├── control ├── postinst ├── postrm ├── preinst ├── prerm └── rules ├── gea.c ├── gea.h ├── gea_test.c ├── gea_test.ok ├── gprs_cipher.h ├── ifc.cpp ├── kasumi.c ├── kasumi.h ├── kasumi_test.c ├── kasumi_test.ok ├── linuxlist.h ├── utils.c └── utils.h /.gitignore: -------------------------------------------------------------------------------- 1 | ._* 2 | *.o 3 | *.so 4 | *.so.* 5 | build-arch-stamp 6 | build-indep-stamp 7 | debian/*debhelper* 8 | debian/files 9 | debian/substvars 10 | debian/liba53* 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | compiler: gcc 3 | 4 | notifications: 5 | irc: 6 | channels: 7 | - "chat.freenode.net#openbts" 8 | template: 9 | - "%{repository} : %{message} : %{build_url}" 10 | on_success: change 11 | on_failure: always 12 | 13 | #before_install: 14 | # - sudo apt-get install -qq libxyz 15 | 16 | #install: 17 | # - sh bootstrap.sh 18 | 19 | script: 20 | - dpkg-buildpackage -us -uc 21 | 22 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RangeNetworks/liba53/27354560dc7b554e03d40a520d41290e731193b6/ChangeLog -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DESTDIR := 2 | 3 | SOURCE_FILES=a5.c bits.c gea.c kasumi.c utils.c ifc.cpp 4 | OBJECT_FILES=a5.o bits.o gea.o kasumi.o utils.o ifc.o 5 | INCLUDE_FILES=a5.h bits.h gea.h gprs_cipher.h kasumi.h linuxlist.h utils.h 6 | 7 | # build A5/3 library 8 | liba53.so.1.0: ${SOURCE_FILES} ${INCLUDE_FILES} Makefile 9 | g++ -O3 -Wall -fPIC -c ${SOURCE_FILES} 10 | g++ -shared -Wl,-soname,liba53.so.1 -o liba53.so.1.0 ${OBJECT_FILES} 11 | ln -sf liba53.so.1.0 liba53.so.1 12 | ln -sf liba53.so.1.0 liba53.so 13 | 14 | # install A5/3 library 15 | install: liba53.so.1.0 16 | cp liba53.so.1.0 $(DESTDIR)/usr/lib 17 | cp -P liba53.so.1 $(DESTDIR)/usr/lib 18 | cp -P liba53.so $(DESTDIR)/usr/lib 19 | cp a53.h $(DESTDIR)/usr/include 20 | 21 | # test installed A5/3 library 22 | installtest: install 23 | g++ -o a53test a53test.cpp -I$(DESTDIR)/usr/include -L$(DESTDIR)/usr/lib -la53 24 | ./a53test 25 | 26 | clean: 27 | rm -f ${OBJECT_FILES} liba53.so* a53test 28 | 29 | # otest: a5_test kasumi_test gea_test a5_speed 30 | # ./a5_test | diff - a5_test.ok 31 | # # ./kasumi_test | diff - kasumi_test.ok 32 | # # ./gea_test | diff - gea_test.ok 33 | # ./a5_speed 34 | # 35 | # a5_speed: a5_speed.c ${SOURCE_FILES} ${INCLUDE_FILES} Makefile 36 | # g++ ${OPT} -o a5_speed a5_speed.c ${SOURCE_FILES} 37 | # 38 | # a5_test: a5_test.c ${SOURCE_FILES} ${INCLUDE_FILES} Makefile 39 | # g++ ${OPT} -o a5_test a5_test.c ${SOURCE_FILES} 40 | # 41 | # # kasumi_test: kasumi_test.c ${SOURCE_FILES} ${INCLUDE_FILES} Makefile 42 | # # g++ ${OPT} -o kasumi_test kasumi_test.c ${SOURCE_FILES} 43 | # 44 | # # gea_test: gea_test.c ${SOURCE_FILES} ${INCLUDE_FILES} Makefile 45 | # # g++ ${OPT} -o gea_test gea_test.c ${SOURCE_FILES} 46 | # 47 | # clean: 48 | # rm a5_test kasumi_test gea_test a5_speed 49 | # 50 | # 51 | # 52 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | to build A5/3 library: 2 | make 3 | 4 | to install A5/3 library: 5 | make install 6 | 7 | to test installed A5/3 library: 8 | make installtest 9 | 10 | installed files: 11 | /usr/lib/liba53.so 12 | /usr/lib/liba53.so.1 13 | /usr/lib/liba53.so.1.0 14 | /usr/include/a53.h 15 | -------------------------------------------------------------------------------- /a5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * a5.c 3 | * 4 | * Full reimplementation of A5/1,2 (split and threadsafe) 5 | * 6 | * The logic behind the algorithm is taken from "A pedagogical implementation 7 | * of the GSM A5/1 and A5/2 "voice privacy" encryption algorithms." by 8 | * Marc Briceno, Ian Goldberg, and David Wagner. 9 | * 10 | * Copyright (C) 2011 Sylvain Munaut 11 | * 12 | * All Rights Reserved 13 | * 14 | * This program is free software; you can redistribute it and/or modify 15 | * it under the terms of the GNU General Public License as published by 16 | * the Free Software Foundation; either version 2 of the License, or 17 | * (at your option) any later version. 18 | * 19 | * This program is distributed in the hope that it will be useful, 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | * GNU General Public License for more details. 23 | * 24 | * You should have received a copy of the GNU General Public License along 25 | * with this program; if not, write to the Free Software Foundation, Inc., 26 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 27 | */ 28 | 29 | /*! \addtogroup a5 30 | * @{ 31 | */ 32 | 33 | /*! \file gsm/a5.c 34 | * \brief Osmocom GSM A5 ciphering algorithm implementation 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "bits.h" 43 | #include "a5.h" 44 | #include "kasumi.h" 45 | 46 | /*! \brief Main method to generate a A5/x cipher stream 47 | * \param[in] n Which A5/x method to use 48 | * \param[in] key 8 byte array for the key (as received from the SIM) 49 | * \param[in] fn Frame number 50 | * \param[out] dl Pointer to array of ubits to return Downlink cipher stream 51 | * \param[out] ul Pointer to array of ubits to return Uplink cipher stream 52 | * 53 | * Currently A5/[0-4] are supported: -ENOTSUP returned in this case, 0 returned for supported ciphers. 54 | * Either (or both) of dl/ul can be NULL if not needed. 55 | */ 56 | void 57 | osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul) 58 | { 59 | switch (n) 60 | { 61 | case 0: 62 | if (dl) 63 | memset(dl, 0x00, 114); 64 | if (ul) 65 | memset(ul, 0x00, 114); 66 | break; 67 | 68 | case 1: 69 | osmo_a5_1(key, fn, dl, ul); 70 | break; 71 | 72 | case 2: 73 | osmo_a5_2(key, fn, dl, ul); 74 | break; 75 | 76 | case 3: 77 | osmo_a5_3(key, fn, dl, ul); 78 | break; 79 | case 4: 80 | osmo_a5_4(key, fn, dl, ul); 81 | break; 82 | 83 | default: 84 | /* a5/[5..7] not supported here/yet */ 85 | 86 | break; 87 | } 88 | } 89 | 90 | 91 | /* ------------------------------------------------------------------------ */ 92 | /* A5/1&2 common stuff */ 93 | /* ------------------------------------------------------------------------ */ 94 | 95 | #define A5_R1_LEN 19 96 | #define A5_R2_LEN 22 97 | #define A5_R3_LEN 23 98 | #define A5_R4_LEN 17 /* A5/2 only */ 99 | 100 | #define A5_R1_MASK ((1<> 16; 118 | x ^= x >> 8; 119 | x ^= x >> 4; 120 | x &= 0xf; 121 | return (0x6996 >> x) & 1; 122 | } 123 | 124 | /*! \brief Compute majority bit from 3 taps 125 | * \param[in] v1 LFSR state ANDed with tap-bit 126 | * \param[in] v2 LFSR state ANDed with tap-bit 127 | * \param[in] v3 LFSR state ANDed with tap-bit 128 | * \return The majority bit (0 or 1) 129 | */ 130 | static inline uint32_t 131 | _a5_12_majority(uint32_t v1, uint32_t v2, uint32_t v3) 132 | { 133 | return (!!v1 + !!v2 + !!v3) >= 2; 134 | } 135 | 136 | /*! \brief Compute the next LFSR state 137 | * \param[in] r Current state 138 | * \param[in] mask LFSR mask 139 | * \param[in] taps LFSR taps 140 | * \return Next state 141 | */ 142 | static inline uint32_t 143 | _a5_12_clock(uint32_t r, uint32_t mask, uint32_t taps) 144 | { 145 | return ((r << 1) & mask) | _a5_12_parity(r & taps); 146 | } 147 | 148 | 149 | /* ------------------------------------------------------------------------ */ 150 | /* A5/1 */ 151 | /* ------------------------------------------------------------------------ */ 152 | 153 | #define A51_R1_CLKBIT 0x000100 154 | #define A51_R2_CLKBIT 0x000400 155 | #define A51_R3_CLKBIT 0x000400 156 | 157 | /*! \brief GSM A5/1 Clocking function 158 | * \param[in] r Register state 159 | * \param[in] force Non-zero value disable conditional clocking 160 | */ 161 | static inline void 162 | _a5_1_clock(uint32_t r[], int force) 163 | { 164 | int cb[3], maj; 165 | 166 | cb[0] = !!(r[0] & A51_R1_CLKBIT); 167 | cb[1] = !!(r[1] & A51_R2_CLKBIT); 168 | cb[2] = !!(r[2] & A51_R3_CLKBIT); 169 | 170 | maj = _a5_12_majority(cb[0], cb[1], cb[2]); 171 | 172 | if (force || (maj == cb[0])) 173 | r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS); 174 | 175 | if (force || (maj == cb[1])) 176 | r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS); 177 | 178 | if (force || (maj == cb[2])) 179 | r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS); 180 | } 181 | 182 | /*! \brief GSM A5/1 Output function 183 | * \param[in] r Register state 184 | * \return The A5/1 output function bit 185 | */ 186 | static inline uint8_t 187 | _a5_1_get_output(uint32_t r[]) 188 | { 189 | return (r[0] >> (A5_R1_LEN-1)) ^ 190 | (r[1] >> (A5_R2_LEN-1)) ^ 191 | (r[2] >> (A5_R3_LEN-1)); 192 | } 193 | 194 | /*! \brief Generate a GSM A5/1 cipher stream 195 | * \param[in] key 8 byte array for the key (as received from the SIM) 196 | * \param[in] fn Frame number 197 | * \param[out] dl Pointer to array of ubits to return Downlink cipher stream 198 | * \param[out] ul Pointer to array of ubits to return Uplink cipher stream 199 | * 200 | * Either (or both) of dl/ul can be NULL if not needed. 201 | */ 202 | void 203 | osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul) 204 | { 205 | uint32_t r[3] = {0, 0, 0}; 206 | uint32_t fn_count; 207 | uint32_t b; 208 | int i; 209 | 210 | /* Key load */ 211 | for (i=0; i<64; i++) 212 | { 213 | b = ( key[7 - (i>>3)] >> (i&7) ) & 1; 214 | 215 | _a5_1_clock(r, 1); 216 | 217 | r[0] ^= b; 218 | r[1] ^= b; 219 | r[2] ^= b; 220 | } 221 | 222 | /* Frame count load */ 223 | fn_count = osmo_a5_fn_count(fn); 224 | 225 | for (i=0; i<22; i++) 226 | { 227 | b = (fn_count >> i) & 1; 228 | 229 | _a5_1_clock(r, 1); 230 | 231 | r[0] ^= b; 232 | r[1] ^= b; 233 | r[2] ^= b; 234 | } 235 | 236 | /* Mix */ 237 | for (i=0; i<100; i++) 238 | { 239 | _a5_1_clock(r, 0); 240 | } 241 | 242 | /* Output */ 243 | for (i=0; i<114; i++) { 244 | _a5_1_clock(r, 0); 245 | if (dl) 246 | dl[i] = _a5_1_get_output(r); 247 | } 248 | 249 | for (i=0; i<114; i++) { 250 | _a5_1_clock(r, 0); 251 | if (ul) 252 | ul[i] = _a5_1_get_output(r); 253 | } 254 | } 255 | 256 | 257 | /* ------------------------------------------------------------------------ */ 258 | /* A5/2 */ 259 | /* ------------------------------------------------------------------------ */ 260 | 261 | #define A52_R4_CLKBIT0 0x000400 262 | #define A52_R4_CLKBIT1 0x000008 263 | #define A52_R4_CLKBIT2 0x000080 264 | 265 | /*! \brief GSM A5/2 Clocking function 266 | * \param[in] r Register state 267 | * \param[in] force Non-zero value disable conditional clocking 268 | */ 269 | static inline void 270 | _a5_2_clock(uint32_t r[], int force) 271 | { 272 | int cb[3], maj; 273 | 274 | cb[0] = !!(r[3] & A52_R4_CLKBIT0); 275 | cb[1] = !!(r[3] & A52_R4_CLKBIT1); 276 | cb[2] = !!(r[3] & A52_R4_CLKBIT2); 277 | 278 | maj = (cb[0] + cb[1] + cb[2]) >= 2; 279 | 280 | if (force || (maj == cb[0])) 281 | r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS); 282 | 283 | if (force || (maj == cb[1])) 284 | r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS); 285 | 286 | if (force || (maj == cb[2])) 287 | r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS); 288 | 289 | r[3] = _a5_12_clock(r[3], A5_R4_MASK, A5_R4_TAPS); 290 | } 291 | 292 | /*! \brief GSM A5/2 Output function 293 | * \param[in] r Register state 294 | * \return The A5/2 output function bit 295 | */ 296 | static inline uint8_t 297 | _a5_2_get_output(uint32_t r[]) 298 | { 299 | uint8_t b; 300 | 301 | b = (r[0] >> (A5_R1_LEN-1)) ^ 302 | (r[1] >> (A5_R2_LEN-1)) ^ 303 | (r[2] >> (A5_R3_LEN-1)) ^ 304 | _a5_12_majority( r[0] & 0x08000, ~r[0] & 0x04000, r[0] & 0x1000) ^ 305 | _a5_12_majority(~r[1] & 0x10000, r[1] & 0x02000, r[1] & 0x0200) ^ 306 | _a5_12_majority( r[2] & 0x40000, r[2] & 0x10000, ~r[2] & 0x2000); 307 | 308 | return b; 309 | } 310 | 311 | /*! \brief Generate a GSM A5/1 cipher stream 312 | * \param[in] key 8 byte array for the key (as received from the SIM) 313 | * \param[in] fn Frame number 314 | * \param[out] dl Pointer to array of ubits to return Downlink cipher stream 315 | * \param[out] ul Pointer to array of ubits to return Uplink cipher stream 316 | * 317 | * Either (or both) of dl/ul can be NULL if not needed. 318 | */ 319 | void 320 | osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul) 321 | { 322 | uint32_t r[4] = {0, 0, 0, 0}; 323 | uint32_t fn_count; 324 | uint32_t b; 325 | int i; 326 | 327 | /* Key load */ 328 | for (i=0; i<64; i++) 329 | { 330 | b = ( key[7 - (i>>3)] >> (i&7) ) & 1; 331 | 332 | _a5_2_clock(r, 1); 333 | 334 | r[0] ^= b; 335 | r[1] ^= b; 336 | r[2] ^= b; 337 | r[3] ^= b; 338 | } 339 | 340 | /* Frame count load */ 341 | fn_count = osmo_a5_fn_count(fn); 342 | 343 | for (i=0; i<22; i++) 344 | { 345 | b = (fn_count >> i) & 1; 346 | 347 | _a5_2_clock(r, 1); 348 | 349 | r[0] ^= b; 350 | r[1] ^= b; 351 | r[2] ^= b; 352 | r[3] ^= b; 353 | } 354 | 355 | r[0] |= 1 << 15; 356 | r[1] |= 1 << 16; 357 | r[2] |= 1 << 18; 358 | r[3] |= 1 << 10; 359 | 360 | /* Mix */ 361 | for (i=0; i<99; i++) 362 | { 363 | _a5_2_clock(r, 0); 364 | } 365 | 366 | /* Output */ 367 | for (i=0; i<114; i++) { 368 | _a5_2_clock(r, 0); 369 | if (dl) 370 | dl[i] = _a5_2_get_output(r); 371 | } 372 | 373 | for (i=0; i<114; i++) { 374 | _a5_2_clock(r, 0); 375 | if (ul) 376 | ul[i] = _a5_2_get_output(r); 377 | } 378 | } 379 | 380 | /* ------------------------------------------------------------------------ */ 381 | /* A5/3 */ 382 | /* ------------------------------------------------------------------------ */ 383 | 384 | /*! \brief Generate a GSM A5/3 cipher stream 385 | * \param[in] key 8 byte array for the key (as received from the SIM) 386 | * \param[in] fn Frame number 387 | * \param[out] dl Pointer to array of ubits to return Downlink cipher stream 388 | * \param[out] ul Pointer to array of ubits to return Uplink cipher stream 389 | * 390 | * Either (or both) of dl/ul should be NULL if not needed. 391 | * 392 | * Implementation based on specifications from 3GPP TS 55.216, 3GPP TR 55.919 and ETSI TS 135 202 393 | * with slight simplifications (CE hardcoded to 0). 394 | */ 395 | void 396 | osmo_a5_3(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul) 397 | { 398 | /* internal function require 128 bit key so we expand by concatenating supplied 64 bit key */ 399 | uint8_t ck[16]; 400 | memcpy(ck, key, 8); 401 | memcpy(ck + 8, key, 8); 402 | 403 | osmo_a5_4(ck, fn, dl, ul); 404 | } 405 | 406 | void 407 | osmo_a5_4(const uint8_t *ck, uint32_t fn, ubit_t *dl, ubit_t *ul) 408 | { 409 | uint8_t i, gamma[32]; 410 | 411 | if (ul) { 412 | _kasumi_kgcore(0xF, 0, fn, 0, ck, gamma, 228); 413 | uint8_t uplink[15]; 414 | for(i = 0; i < 15; i++) uplink[i] = (gamma[i + 14] << 2) + (gamma[i + 15] >> 6); 415 | osmo_pbit2ubit(ul, uplink, 114); 416 | } 417 | if (dl) { 418 | _kasumi_kgcore(0xF, 0, fn, 0, ck, gamma, 114); 419 | osmo_pbit2ubit(dl, gamma, 114); 420 | } 421 | } 422 | 423 | /*! @} */ 424 | -------------------------------------------------------------------------------- /a5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * a5.h 3 | * 4 | * Copyright (C) 2011 Sylvain Munaut 5 | * 6 | * All Rights Reserved 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifndef __OSMO_A5_H__ 24 | #define __OSMO_A5_H__ 25 | 26 | #include 27 | #include 28 | 29 | #include "bits.h" 30 | 31 | /*! \defgroup a5 GSM A5 ciphering algorithm 32 | * @{ 33 | */ 34 | 35 | /*! \file gsm/a5.h 36 | * \brief Osmocom GSM A5 ciphering algorithm header 37 | */ 38 | 39 | /*! \brief Converts a frame number into the 22 bit number used in A5/x 40 | * \param[in] fn The true framenumber 41 | * \return 22 bit word 42 | */ 43 | static inline uint32_t 44 | osmo_a5_fn_count(uint32_t fn) 45 | { 46 | int t1 = fn / (26 * 51); 47 | int t2 = fn % 26; 48 | int t3 = fn % 51; 49 | return (t1 << 11) | (t3 << 5) | t2; 50 | } 51 | 52 | /* Notes: 53 | * - key must be 8 bytes long (or NULL for A5/0) 54 | * - the dl and ul pointer must be either NULL or 114 bits long 55 | * - fn is the _real_ GSM frame number. 56 | * (converted internally to fn_count) 57 | */ 58 | void osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul); 59 | void osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul); 60 | void osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul); 61 | void osmo_a5_3(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul); 62 | void osmo_a5_4(const uint8_t *ck, uint32_t fn, ubit_t *dl, ubit_t *ul); 63 | 64 | /*! @} */ 65 | 66 | #endif /* __OSMO_A5_H__ */ 67 | -------------------------------------------------------------------------------- /a53.h: -------------------------------------------------------------------------------- 1 | typedef unsigned char u8; 2 | typedef unsigned short u16; 3 | typedef unsigned int u32; 4 | 5 | void A53_GSM( u8 *key, int klen, int count, u8 *block1, u8 *block2 ); 6 | -------------------------------------------------------------------------------- /a53test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | void printer(int which, const char *label, u8 *vector, int lth) 9 | { 10 | cout << " block" << which << " " << label << " = "; 11 | int i; 12 | for (i = 0; i < lth; i++) { 13 | cout << hex << std::setw(2) << setfill('0') << (int)vector[i] << dec; 14 | } 15 | } 16 | 17 | void check(int which, u8 *exp, u8 *got) 18 | { 19 | printer(which, "exp", exp, 15); 20 | printer(which, "got", got, 15); 21 | int err = 0; 22 | int i; 23 | for (i = 0; i < 15; i++) { 24 | if (exp[i] == got[i]) continue; 25 | err = 1; 26 | break; 27 | } 28 | if (err) { 29 | cout << " ERROR" << endl; 30 | } else { 31 | cout << " ok" << endl; 32 | } 33 | } 34 | 35 | int unhex(const char c) 36 | { 37 | if (c >= '0' && c <= '9') return c - '0'; 38 | if (c >= 'A' && c <= 'F') return c - 'A' + 10; 39 | cout << "oops" << endl; 40 | exit(1); 41 | } 42 | 43 | int seti(const char *src) 44 | { 45 | int r = 0; 46 | for ( ; *src != 0; src++) { 47 | r = (r << 4) + unhex(*src); 48 | } 49 | return r; 50 | } 51 | 52 | void setu8(u8 *dst, const char *src) 53 | { 54 | for ( ; *src != 0; src += 2) { 55 | *dst++ = (unhex(src[0]) << 4) | (unhex(src[1])); 56 | } 57 | } 58 | 59 | int main() 60 | { 61 | int i, keylth; 62 | unsigned int count; 63 | u8 key[16], exp1[15], exp2[15], got1[15], got2[15]; 64 | const char *data[52] = { 65 | "2BD6459F82C5BC00", "24F20F", "889EEAAF9ED1BA1ABBD8436232E440", "5CA3406AA244CF69CF047AADA2DF40", 66 | "952C49104881FF48", "061527", "AB7DB38A573A325DAA76E4CB800A40", "4C4B594FEA9D00FE8978B7B7BC1080", 67 | "EFA8B2229E720C2A", "33FD3F", "0E4015755A336469C3DD8680E30340", "6F10669E2B4E18B042431A28E47F80", 68 | "3451F23A43BD2C87", "0E418C", "75F7C4C51560905DFBA05E46FB54C0", "192C95353CDF979E054186DF15BF00", 69 | "CAA2639BE82435CF", "2FF229", "301437E4D4D6565D4904C631606EC0", "F0A3B8795E264D3E1A82F684353DC0", 70 | "7AE67E87400B9FA6", "2F24E5", "F794290FEF643D2EA348A7796A2100", "CB6FA6C6B8A705AF9FEFE975818500", 71 | "58AF69935540698B", "05446B", "749CA4E6B691E5A598C461D5FE4740", "31C9E444CD04677ADAA8A082ADBC40", 72 | "017F81E5F236FE62", "156B26", "2A6976761E60CC4E8F9F52160276C0", "A544D8475F2C78C35614128F1179C0", 73 | "1ACA8B448B767B39", "0BC3B5", "A4F70DC5A2C9707F5FA1C60EB10640", "7780B597B328C1400B5C74823E8500", 74 | // "5ACB1D644C0D512041A5", "1D5157", "8EFAEC49C355CCD995C2BF649FD480", "F3A2910CAEDF587E976171AAF33B80", 75 | // "9315819243A043BEBE6E", "2E196F", "AA08DB46DD3DED78A612085C529D00", "0250463DA0E3886F9BC2E3BB0D73C0", 76 | // "3D43C388C9581E337FF1F97EB5C1F85E", "35D2CF", "A2FE3034B6B22CC4E33C7090BEC340", "170D7497432FF897B91BE8AECBA880", 77 | // "A4496A64DF4F399F3B4506814A3E07A1", "212777", "89CDEE360DF9110281BCF57755A040", "33822C0C779598C9CBFC49183AF7C0", 78 | }; 79 | for (i = 32; i>=0; i-=4) { 80 | cout << "test set " << (1+i/4) << endl; 81 | setu8(key, data[i]); 82 | keylth = strlen(data[i])*4; 83 | count = seti(data[i+1]); 84 | A53_GSM(key, keylth, count, got1, got2); 85 | setu8(exp1, data[i+2]); 86 | setu8(exp2, data[i+3]); 87 | check(1, exp1, got1); 88 | check(2, exp2, got2); 89 | } 90 | cout << "time test" << endl; 91 | int n = 10000; 92 | float t = clock(); 93 | for (i = 0; i < n; i++) { 94 | A53_GSM(key, keylth, count, got1, got2); 95 | } 96 | t = (clock() - t) / (CLOCKS_PER_SEC * (float)n); 97 | cout << "GSM takes " << t << " seconds per iteration" << endl; 98 | exit(0); 99 | } 100 | -------------------------------------------------------------------------------- /a5_speed.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "bits.h" 9 | #include "utils.h" 10 | #include "a5.h" 11 | 12 | static const uint8_t key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; 13 | static const uint32_t fn = 123456; 14 | static const uint8_t dl[] = { 15 | /* A5/0 */ 16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 18 | 19 | /* A5/1 */ 20 | 0xcb, 0xa2, 0x55, 0x76, 0x17, 0x5d, 0x3b, 0x1c, 21 | 0x7b, 0x2f, 0x29, 0xa8, 0xc1, 0xb6, 0x00, 22 | 23 | /* A5/2 */ 24 | 0x45, 0x9c, 0x88, 0xc3, 0x82, 0xb7, 0xff, 0xb3, 25 | 0x98, 0xd2, 0xf9, 0x6e, 0x0f, 0x14, 0x80, 26 | }; 27 | static const uint8_t ul[] = { 28 | /* A5/0 */ 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31 | 32 | /* A5/1 */ 33 | 0xd9, 0x03, 0x5e, 0x0f, 0x2a, 0xec, 0x13, 0x9a, 34 | 0x05, 0xd4, 0xa8, 0x7b, 0xb1, 0x64, 0x80, 35 | 36 | /* A5/2 */ 37 | 0xf0, 0x3a, 0xac, 0xde, 0xe3, 0x5b, 0x5e, 0x65, 38 | 0x80, 0xba, 0xab, 0xc0, 0x59, 0x26, 0x40, 39 | }; 40 | 41 | void test_a5(int n, char * kc, uint32_t count, char * block1, char * block2) { 42 | ubit_t out[114]; 43 | int k = (n == 4) ? 16 : 8; 44 | int ntrials; 45 | float t; 46 | int i; 47 | uint8_t key[k]; 48 | osmo_hexparse(kc, key, k); 49 | ntrials = 10000; 50 | 51 | t = clock(); 52 | for (i = 0; i < ntrials; i++) { 53 | osmo_a5(n, key, count, out, NULL); 54 | } 55 | t = (clock() - t) / (CLOCKS_PER_SEC * (float)ntrials); 56 | printf("osmo_a5 DL takes %g seconds per iteration\n", t); 57 | 58 | t = clock(); 59 | for (i = 0; i < ntrials; i++) { 60 | osmo_a5(n, key, count, NULL, out); 61 | } 62 | t = (clock() - t) / (CLOCKS_PER_SEC * (float)ntrials); 63 | printf("osmo_a5 UL takes %g seconds per iteration\n", t); 64 | 65 | } 66 | 67 | int main(int argc, char **argv) 68 | { 69 | test_a5(3, "2BD6459F82C5BC00", 0x24F20F, "889EEAAF9ED1BA1ABBD8436232E440", "5CA3406AA244CF69CF047AADA2DF40"); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /a5_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "bits.h" 8 | #include "utils.h" 9 | #include "a5.h" 10 | 11 | static const uint8_t key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; 12 | static const uint32_t fn = 123456; 13 | static const uint8_t dl[] = { 14 | /* A5/0 */ 15 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17 | 18 | /* A5/1 */ 19 | 0xcb, 0xa2, 0x55, 0x76, 0x17, 0x5d, 0x3b, 0x1c, 20 | 0x7b, 0x2f, 0x29, 0xa8, 0xc1, 0xb6, 0x00, 21 | 22 | /* A5/2 */ 23 | 0x45, 0x9c, 0x88, 0xc3, 0x82, 0xb7, 0xff, 0xb3, 24 | 0x98, 0xd2, 0xf9, 0x6e, 0x0f, 0x14, 0x80, 25 | }; 26 | static const uint8_t ul[] = { 27 | /* A5/0 */ 28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 | 31 | /* A5/1 */ 32 | 0xd9, 0x03, 0x5e, 0x0f, 0x2a, 0xec, 0x13, 0x9a, 33 | 0x05, 0xd4, 0xa8, 0x7b, 0xb1, 0x64, 0x80, 34 | 35 | /* A5/2 */ 36 | 0xf0, 0x3a, 0xac, 0xde, 0xe3, 0x5b, 0x5e, 0x65, 37 | 0x80, 0xba, 0xab, 0xc0, 0x59, 0x26, 0x40, 38 | }; 39 | 40 | inline bool print_a5(int n, int k, char * dir, ubit_t * out, char * block) { 41 | uint8_t len = 114 / 8 + 1, buf[len], res[len]; 42 | printf("A5/%d - %s: %s => ", n, dir, osmo_ubit_dump(out, 114)); 43 | osmo_hexparse(block, res, len); 44 | osmo_ubit2pbit(buf, out, 114); 45 | if (0 != memcmp(buf, res, len)) { 46 | printf("FAIL"); 47 | printf("\nGOT: [%d] %s", k, osmo_hexdump_nospc(buf, len)); 48 | printf("\nEXP: [%d] %s\n", k, osmo_hexdump_nospc(res, len)); 49 | return false; 50 | } 51 | printf("OK\n"); 52 | return true; 53 | } 54 | 55 | inline bool test_a5(int n, char * kc, uint32_t count, char * block1, char * block2) { 56 | ubit_t out[114]; 57 | int k = (n == 4) ? 16 : 8; 58 | uint8_t key[k]; 59 | osmo_hexparse(kc, key, k); 60 | 61 | osmo_a5(n, key, count, out, NULL); 62 | bool d = print_a5(n, k, "DL", out, block1); 63 | 64 | osmo_a5(n, key, count, NULL, out); 65 | bool u = print_a5(n, k, "UL", out, block2); 66 | 67 | return d & u; 68 | } 69 | 70 | int main(int argc, char **argv) 71 | { 72 | ubit_t exp[114], out[114]; 73 | int n, i; 74 | 75 | for (n=0; n<3; n++) { 76 | /* "Randomize" */ 77 | for (i=0; i<114; i++) 78 | out[i] = i & 1; 79 | 80 | /* DL */ 81 | osmo_pbit2ubit(exp, &dl[15*n], 114); 82 | 83 | osmo_a5(n, key, fn, out, NULL); 84 | 85 | printf("A5/%d - DL: %s", n, osmo_ubit_dump(out, 114)); 86 | 87 | if (!memcmp(exp, out, 114)) 88 | printf(" => OK\n"); 89 | else { 90 | printf(" => BAD\n"); 91 | printf(" Expected: %s", osmo_ubit_dump(out, 114)); 92 | fprintf(stderr, "[!] A5/%d DL failed", n); 93 | exit(1); 94 | } 95 | 96 | /* UL */ 97 | osmo_pbit2ubit(exp, &ul[15*n], 114); 98 | 99 | osmo_a5(n, key, fn, NULL, out); 100 | 101 | printf("A5/%d - UL: %s", n, osmo_ubit_dump(out, 114)); 102 | 103 | if (!memcmp(exp, out, 114)) 104 | printf(" => OK\n"); 105 | else { 106 | printf(" => BAD\n"); 107 | printf(" Expected: %s", osmo_ubit_dump(out, 114)); 108 | fprintf(stderr, "[!] A5/%d UL failed", n); 109 | exit(1); 110 | } 111 | } 112 | 113 | // test vectors from 3GPP TS 55.217 and TS 55.218 114 | test_a5(3, "2BD6459F82C5BC00", 0x24F20F, "889EEAAF9ED1BA1ABBD8436232E440", "5CA3406AA244CF69CF047AADA2DF40"); 115 | test_a5(3, "952C49104881FF48", 0x061272, "FB4D5FBCEE13A33389285686E9A5C0", "25090378E0540457C57E367662E440"); 116 | test_a5(3, "EFA8B2229E720C2A", 0x33FD3F, "0E4015755A336469C3DD8680E30340", "6F10669E2B4E18B042431A28E47F80"); 117 | test_a5(3, "952C49104881FF48", 0x061527, "AB7DB38A573A325DAA76E4CB800A40", "4C4B594FEA9D00FE8978B7B7BC1080"); 118 | test_a5(3, "3451F23A43BD2C87", 0x0E418C, "75F7C4C51560905DFBA05E46FB54C0", "192C95353CDF979E054186DF15BF00"); 119 | test_a5(3, "CAA2639BE82435CF", 0x2FF229, "301437E4D4D6565D4904C631606EC0", "F0A3B8795E264D3E1A82F684353DC0"); 120 | test_a5(3, "7AE67E87400B9FA6", 0x2F24E5, "F794290FEF643D2EA348A7796A2100", "CB6FA6C6B8A705AF9FEFE975818500"); 121 | test_a5(3, "58AF69935540698B", 0x05446B, "749CA4E6B691E5A598C461D5FE4740", "31C9E444CD04677ADAA8A082ADBC40"); 122 | test_a5(3, "017F81E5F236FE62", 0x156B26, "2A6976761E60CC4E8F9F52160276C0", "A544D8475F2C78C35614128F1179C0"); 123 | test_a5(3, "1ACA8B448B767B39", 0x0BC3B5, "A4F70DC5A2C9707F5FA1C60EB10640", "7780B597B328C1400B5C74823E8500"); 124 | test_a5(4, "3D43C388C9581E337FF1F97EB5C1F85E", 0x35D2CF, "A2FE3034B6B22CC4E33C7090BEC340", "170D7497432FF897B91BE8AECBA880"); 125 | test_a5(4, "A4496A64DF4F399F3B4506814A3E07A1", 0x212777, "89CDEE360DF9110281BCF57755A040", "33822C0C779598C9CBFC49183AF7C0"); 126 | 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /a5_test.ok: -------------------------------------------------------------------------------- 1 | A5/0 - DL: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 => OK 2 | A5/0 - UL: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 => OK 3 | A5/1 - DL: 110010111010001001010101011101100001011101011101001110110001110001111011001011110010100110101000110000011011011000 => OK 4 | A5/1 - UL: 110110010000001101011110000011110010101011101100000100111001101000000101110101001010100001111011101100010110010010 => OK 5 | A5/2 - DL: 010001011001110010001000110000111000001010110111111111111011001110011000110100101111100101101110000011110001010010 => OK 6 | A5/2 - UL: 111100000011101010101100110111101110001101011011010111100110010110000000101110101010101111000000010110010010011001 => OK 7 | A5/3 - DL: 100010001001111011101010101011111001111011010001101110100001101010111011110110000100001101100010001100101110010001 => OK 8 | A5/3 - UL: 010111001010001101000000011010101010001001000100110011110110100111001111000001000111101010101101101000101101111101 => OK 9 | A5/3 - DL: 111110110100110101011111101111001110111000010011101000110011001110001001001010000101011010000110111010011010010111 => OK 10 | A5/3 - UL: 001001010000100100000011011110001110000001010100000001000101011111000101011111100011011001110110011000101110010001 => OK 11 | A5/3 - DL: 000011100100000000010101011101010101101000110011011001000110100111000011110111011000011010000000111000110000001101 => OK 12 | A5/3 - UL: 011011110001000001100110100111100010101101001110000110001011000001000010010000110001101000101000111001000111111110 => OK 13 | A5/3 - DL: 101010110111110110110011100010100101011100111010001100100101110110101010011101101110010011001011100000000000101001 => OK 14 | A5/3 - UL: 010011000100101101011001010011111110101010011101000000001111111010001001011110001011011110110111101111000001000010 => OK 15 | A5/3 - DL: 011101011111011111000100110001010001010101100000100100000101110111111011101000000101111001000110111110110101010011 => OK 16 | A5/3 - UL: 000110010010110010010101001101010011110011011111100101111001111000000101010000011000011011011111000101011011111100 => OK 17 | A5/3 - DL: 001100000001010000110111111001001101010011010110010101100101110101001001000001001100011000110001011000000110111011 => OK 18 | A5/3 - UL: 111100001010001110111000011110010101111000100110010011010011111000011010100000101111011010000100001101010011110111 => OK 19 | A5/3 - DL: 111101111001010000101001000011111110111101100100001111010010111010100011010010001010011101111001011010100010000100 => OK 20 | A5/3 - UL: 110010110110111110100110110001101011100010100111000001011010111110011111111011111110100101110101100000011000010100 => OK 21 | A5/3 - DL: 011101001001110010100100111001101011011010010001111001011010010110011000110001000110000111010101111111100100011101 => OK 22 | A5/3 - UL: 001100011100100111100100010001001100110100000100011001110111101011011010101010001010000010000010101011011011110001 => OK 23 | A5/3 - DL: 001010100110100101110110011101100001111001100000110011000100111010001111100111110101001000010110000000100111011011 => OK 24 | A5/3 - UL: 101001010100010011011000010001110101111100101100011110001100001101010110000101000001001010001111000100010111100111 => OK 25 | A5/3 - DL: 101001001111011100001101110001011010001011001001011100000111111101011111101000011100011000001110101100010000011001 => OK 26 | A5/3 - UL: 011101111000000010110101100101111011001100101000110000010100000000001011010111000111010010000010001111101000010100 => OK 27 | A5/4 - DL: 101000101111111000110000001101001011011010110010001011001100010011100011001111000111000010010000101111101100001101 => OK 28 | A5/4 - UL: 000101110000110101110100100101110100001100101111111110001001011110111001000110111110100010101110110010111010100010 => OK 29 | A5/4 - DL: 100010011100110111101110001101100000110111111001000100010000001010000001101111001111010101110111010101011010000001 => OK 30 | A5/4 - UL: 001100111000001000101100000011000111011110010101100110001100100111001011111111000100100100011000001110101111011111 => OK 31 | -------------------------------------------------------------------------------- /bits.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "bits.h" 5 | 6 | /*! \addtogroup bits 7 | * @{ 8 | */ 9 | 10 | /*! \file bits.c 11 | * \brief Osmocom bit level support code 12 | */ 13 | 14 | 15 | /*! \brief convert unpacked bits to packed bits, return length in bytes 16 | * \param[out] out output buffer of packed bits 17 | * \param[in] in input buffer of unpacked bits 18 | * \param[in] num_bits number of bits 19 | */ 20 | int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits) 21 | { 22 | unsigned int i; 23 | uint8_t curbyte = 0; 24 | pbit_t *outptr = out; 25 | 26 | for (i = 0; i < num_bits; i++) { 27 | uint8_t bitnum = 7 - (i % 8); 28 | 29 | curbyte |= (in[i] << bitnum); 30 | 31 | if(i % 8 == 7){ 32 | *outptr++ = curbyte; 33 | curbyte = 0; 34 | } 35 | } 36 | /* we have a non-modulo-8 bitcount */ 37 | if (i % 8) 38 | *outptr++ = curbyte; 39 | 40 | return outptr - out; 41 | } 42 | 43 | /*! \brief convert packed bits to unpacked bits, return length in bytes 44 | * \param[out] out output buffer of unpacked bits 45 | * \param[in] in input buffer of packed bits 46 | * \param[in] num_bits number of bits 47 | */ 48 | int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits) 49 | { 50 | unsigned int i; 51 | ubit_t *cur = out; 52 | ubit_t *limit = out + num_bits; 53 | 54 | for (i = 0; i < (num_bits/8)+1; i++) { 55 | pbit_t byte = in[i]; 56 | *cur++ = (byte >> 7) & 1; 57 | if (cur >= limit) 58 | break; 59 | *cur++ = (byte >> 6) & 1; 60 | if (cur >= limit) 61 | break; 62 | *cur++ = (byte >> 5) & 1; 63 | if (cur >= limit) 64 | break; 65 | *cur++ = (byte >> 4) & 1; 66 | if (cur >= limit) 67 | break; 68 | *cur++ = (byte >> 3) & 1; 69 | if (cur >= limit) 70 | break; 71 | *cur++ = (byte >> 2) & 1; 72 | if (cur >= limit) 73 | break; 74 | *cur++ = (byte >> 1) & 1; 75 | if (cur >= limit) 76 | break; 77 | *cur++ = (byte >> 0) & 1; 78 | if (cur >= limit) 79 | break; 80 | } 81 | return cur - out; 82 | } 83 | 84 | /*! \brief convert unpacked bits to packed bits (extended options) 85 | * \param[out] out output buffer of packed bits 86 | * \param[in] out_ofs offset into output buffer 87 | * \param[in] in input buffer of unpacked bits 88 | * \param[in] in_ofs offset into input buffer 89 | * \param[in] num_bits number of bits 90 | * \param[in] lsb_mode Encode bits in LSB orde instead of MSB 91 | * \returns length in bytes (max written offset of output buffer + 1) 92 | */ 93 | int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs, 94 | const ubit_t *in, unsigned int in_ofs, 95 | unsigned int num_bits, int lsb_mode) 96 | { 97 | int op, bn; 98 | for (unsigned i=0; i>3] |= 1 << bn; 103 | else 104 | out[op>>3] &= ~(1 << bn); 105 | } 106 | return ((out_ofs + num_bits - 1) >> 3) + 1; 107 | } 108 | 109 | /*! \brief convert packed bits to unpacked bits (extended options) 110 | * \param[out] out output buffer of unpacked bits 111 | * \param[in] out_ofs offset into output buffer 112 | * \param[in] in input buffer of packed bits 113 | * \param[in] in_ofs offset into input buffer 114 | * \param[in] num_bits number of bits 115 | * \param[in] lsb_mode Encode bits in LSB orde instead of MSB 116 | * \returns length in bytes (max written offset of output buffer + 1) 117 | */ 118 | int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs, 119 | const pbit_t *in, unsigned int in_ofs, 120 | unsigned int num_bits, int lsb_mode) 121 | { 122 | int ip, bn; 123 | for (unsigned i=0; i>3] & (1<> 1; 135 | if (k & 2) x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2; 136 | if (k & 4) x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4; 137 | if (k & 8) x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8; 138 | if (k & 16) x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16; 139 | 140 | return x; 141 | } 142 | 143 | /* generalized bit reversal function, Chapter 7 "Hackers Delight" */ 144 | uint32_t osmo_revbytebits_32(uint32_t x) 145 | { 146 | x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1; 147 | x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2; 148 | x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4; 149 | 150 | return x; 151 | } 152 | 153 | uint32_t osmo_revbytebits_8(uint8_t x) 154 | { 155 | x = (x & 0x55) << 1 | (x & 0xAA) >> 1; 156 | x = (x & 0x33) << 2 | (x & 0xCC) >> 2; 157 | x = (x & 0x0F) << 4 | (x & 0xF0) >> 4; 158 | 159 | return x; 160 | } 161 | 162 | void osmo_revbytebits_buf(uint8_t *buf, int ilen) 163 | { 164 | unsigned int unaligned_cnt; 165 | unsigned len_remain = ilen; 166 | unsigned len = ilen; 167 | 168 | unaligned_cnt = ((unsigned long)buf & 3); 169 | for (unsigned i = 0; i < unaligned_cnt; i++) { 170 | buf[i] = osmo_revbytebits_8(buf[i]); 171 | len_remain--; 172 | if (len_remain <= 0) 173 | return; 174 | } 175 | 176 | for (unsigned i = unaligned_cnt; i < len; i += 4) { 177 | uint32_t *cur = (uint32_t *) (buf + i); 178 | *cur = osmo_revbytebits_32(*cur); 179 | len_remain -= 4; 180 | } 181 | 182 | for (unsigned i = len - len_remain; i < len; i++) { 183 | buf[i] = osmo_revbytebits_8(buf[i]); 184 | len_remain--; 185 | } 186 | } 187 | 188 | void osmo_revbytes_buf(uint8_t *buf, size_t len) 189 | { 190 | uint8_t *end = buf + len - 1, tmp; 191 | 192 | while (buf < end) { 193 | tmp = *buf; 194 | *buf++ = *end; 195 | *end-- = tmp; 196 | } 197 | } 198 | 199 | /* left circular shift */ 200 | uint16_t rol16(uint16_t in, unsigned shift) 201 | { 202 | return (in << shift) | (in >> (16 - shift)); 203 | } 204 | 205 | /* return 2 bytes from a given array glued into single uint16_t */ 206 | uint16_t osmo_get2bytes(const uint8_t *a) 207 | { /* UNSAFE! NO out-of-bounds access check. Do NOT use unless you know what you are doing! */ 208 | return (uint16_t)((((uint16_t)a[0]) << 8) + (uint16_t)a[1]); 209 | } 210 | 211 | /* convert uint64_t into array of 8 bytes in out */ 212 | void osmo_64pack2pbit(uint64_t in, pbit_t *out) 213 | { 214 | int i; 215 | for (i = 7; i >=0; i--) { 216 | out[i] = in & 0xFF; 217 | in >>= 8; 218 | } 219 | } 220 | 221 | /*! @} */ 222 | -------------------------------------------------------------------------------- /bits.h: -------------------------------------------------------------------------------- 1 | #ifndef _OSMO_BITS_H 2 | #define _OSMO_BITS_H 3 | 4 | #include 5 | #include 6 | /*! \defgroup bits soft, unpacked and packed bits 7 | * @{ 8 | */ 9 | 10 | /*! \file bits.h 11 | * \brief Osmocom bit level support code 12 | */ 13 | 14 | typedef int8_t sbit_t; /*!< \brief soft bit (-127...127) */ 15 | typedef uint8_t ubit_t; /*!< \brief unpacked bit (0 or 1) */ 16 | typedef uint8_t pbit_t; /*!< \brief packed bis (8 bits in a byte) */ 17 | 18 | /* 19 | NOTE on the endianess of pbit_t: 20 | Bits in a pbit_t are ordered MSB first, i.e. 0x80 is the first bit. 21 | Bit i in a pbit_t array is array[i/8] & (1<<(7-i%8)) 22 | */ 23 | 24 | /*! \brief determine how many bytes we would need for \a num_bits packed bits 25 | * \param[in] num_bits Number of packed bits 26 | */ 27 | static inline unsigned int osmo_pbit_bytesize(unsigned int num_bits) 28 | { 29 | unsigned int pbit_bytesize = num_bits / 8; 30 | 31 | if (num_bits % 8) 32 | pbit_bytesize++; 33 | 34 | return pbit_bytesize; 35 | } 36 | 37 | int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits); 38 | 39 | int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits); 40 | 41 | int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs, 42 | const ubit_t *in, unsigned int in_ofs, 43 | unsigned int num_bits, int lsb_mode); 44 | 45 | int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs, 46 | const pbit_t *in, unsigned int in_ofs, 47 | unsigned int num_bits, int lsb_mode); 48 | 49 | 50 | /* BIT REVERSAL */ 51 | 52 | /*! \brief bit-reversal mode for osmo_bit_reversal() */ 53 | enum osmo_br_mode { 54 | /*! \brief reverse all bits in a 32bit dword */ 55 | OSMO_BR_BITS_IN_DWORD = 31, 56 | /*! \brief reverse byte order in a 32bit dword */ 57 | OSMO_BR_BYTES_IN_DWORD = 24, 58 | /*! \brief reverse bits of each byte in a 32bit dword */ 59 | OSMO_BR_BITS_IN_BYTE = 7, 60 | /*! \brief swap the two 16bit words in a 32bit dword */ 61 | OSMO_BR_WORD_SWAP = 16, 62 | }; 63 | 64 | /*! \brief generic bit reversal function */ 65 | uint32_t osmo_bit_reversal(uint32_t x, enum osmo_br_mode k); 66 | 67 | /* \brief reverse the bits within each byte of a 32bit word */ 68 | uint32_t osmo_revbytebits_32(uint32_t x); 69 | 70 | /* \brief reverse the bits within a byte */ 71 | uint32_t osmo_revbytebits_8(uint8_t x); 72 | 73 | /* \brief reverse the bits of each byte in a given buffer */ 74 | void osmo_revbytebits_buf(uint8_t *buf, int len); 75 | 76 | /* \brief reverse the order of the bytes in a given buffer */ 77 | void osmo_revbytes_buf(uint8_t *buf, size_t len); 78 | 79 | /* \brief left circular shift */ 80 | uint16_t rol16(uint16_t in, unsigned shift); 81 | 82 | /* return 2 bytes from a given array glued into single uint16_t */ 83 | uint16_t osmo_get2bytes(const uint8_t *a); 84 | 85 | /* convert uint64_t into array of 8 bytes in out */ 86 | void osmo_64pack2pbit(uint64_t in, pbit_t *out); 87 | 88 | /*! @} */ 89 | 90 | #endif /* _OSMO_BITS_H */ 91 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | liba53 (0.1) unstable; urgency=low 2 | 3 | * Initial release 4 | 5 | -- Range Packager Wed, 13 Oct 2014 12:42:00 -0700 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: liba53 2 | Section: comm 3 | Priority: optional 4 | Maintainer: Range Networks, Inc. 5 | Homepage: http://www.rangenetworks.com/ 6 | Build-Depends: build-essential, debhelper (>= 7), pkg-config 7 | Standards-Version: 3.7.3 8 | 9 | Package: liba53 10 | Section: comm 11 | Priority: optional 12 | Architecture: any 13 | Essential: no 14 | Depends: libc6, pkg-config 15 | Description: A5/3 call encryption library 16 | -------------------------------------------------------------------------------- /debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postinst script for test 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | # TODO: For now disable "set -e" since I have not figured out how to get sqlite3 to SHUT UP! 7 | #set -e 8 | 9 | # summary of how this script can be called: 10 | # * `configure' 11 | # * `abort-upgrade' 12 | # * `abort-remove' `in-favour' 13 | # 14 | # * `abort-remove' 15 | # * `abort-deconfigure' `in-favour' 16 | # `removing' 17 | # 18 | # for details, see http://www.debian.org/doc/debian-policy/ or 19 | # the debian-policy package 20 | 21 | 22 | 23 | case "$1" in 24 | configure) 25 | ldconfig 26 | ;; 27 | 28 | abort-upgrade|abort-remove|abort-deconfigure) 29 | ;; 30 | 31 | *) 32 | echo "postinst called with unknown argument \`$1'" >&2 33 | exit 1 34 | ;; 35 | esac 36 | 37 | # dh_installdeb will replace this with shell code automatically 38 | # generated by other debhelper scripts. 39 | 40 | #DEBHELPER# 41 | 42 | exit 0 43 | -------------------------------------------------------------------------------- /debian/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postrm script for test 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `remove' 10 | # * `purge' 11 | # * `upgrade' 12 | # * `failed-upgrade' 13 | # * `abort-install' 14 | # * `abort-install' 15 | # * `abort-upgrade' 16 | # * `disappear' 17 | # 18 | # for details, see http://www.debian.org/doc/debian-policy/ or 19 | # the debian-policy package 20 | 21 | 22 | case "$1" in 23 | purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 24 | ldconfig 25 | ;; 26 | 27 | *) 28 | echo "postrm called with unknown argument \`$1'" >&2 29 | exit 1 30 | ;; 31 | esac 32 | 33 | # dh_installdeb will replace this with shell code automatically 34 | # generated by other debhelper scripts. 35 | 36 | #DEBHELPER# 37 | 38 | exit 0 39 | -------------------------------------------------------------------------------- /debian/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # preinst script for test 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `install' 10 | # * `install' 11 | # * `upgrade' 12 | # * `abort-upgrade' 13 | # for details, see http://www.debian.org/doc/debian-policy/ or 14 | # the debian-policy package 15 | 16 | 17 | case "$1" in 18 | install|upgrade) 19 | ;; 20 | 21 | abort-upgrade) 22 | ;; 23 | 24 | *) 25 | echo "preinst called with unknown argument \`$1'" >&2 26 | exit 1 27 | ;; 28 | esac 29 | 30 | # dh_installdeb will replace this with shell code automatically 31 | # generated by other debhelper scripts. 32 | 33 | #DEBHELPER# 34 | 35 | exit 0 36 | -------------------------------------------------------------------------------- /debian/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # prerm script for test 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `remove' 10 | # * `upgrade' 11 | # * `failed-upgrade' 12 | # * `remove' `in-favour' 13 | # * `deconfigure' `in-favour' 14 | # `removing' 15 | # 16 | # for details, see http://www.debian.org/doc/debian-policy/ or 17 | # the debian-policy package 18 | 19 | 20 | case "$1" in 21 | remove|upgrade|deconfigure) 22 | ;; 23 | 24 | failed-upgrade) 25 | ;; 26 | 27 | *) 28 | echo "prerm called with unknown argument \`$1'" >&2 29 | exit 1 30 | ;; 31 | esac 32 | 33 | # dh_installdeb will replace this with shell code automatically 34 | # generated by other debhelper scripts. 35 | 36 | #DEBHELPER# 37 | 38 | exit 0 39 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # 5 | # This file was originally written by Joey Hess and Craig Small. 6 | # As a special exception, when this file is copied by dh-make into a 7 | # dh-make output file, you may use that output file without restriction. 8 | # This special exception was added by Craig Small in version 0.37 of dh-make. 9 | # 10 | # Modified to make a template file for a multi-binary package with separated 11 | # build-arch and build-indep targets by Bill Allombert 2001 12 | 13 | # Uncomment this to turn on verbose mode. 14 | #export DH_VERBOSE=1 15 | 16 | # Never distribute source control meta information 17 | export DH_ALWAYS_EXCLUDE=.svn:.git 18 | 19 | # This has to be exported to make some magic below work. 20 | export DH_OPTIONS 21 | 22 | configure: 23 | 24 | config: configure-stamp 25 | configure-stamp: configure 26 | dh_testdir 27 | 28 | #Architecture 29 | build: build-arch build-indep 30 | 31 | build-arch: build-arch-stamp 32 | build-arch-stamp: configure-stamp 33 | 34 | # Add here commands to compile the arch part of the package. 35 | #$(MAKE) 36 | touch $@ 37 | 38 | build-indep: build-indep-stamp 39 | build-indep-stamp: configure-stamp 40 | 41 | # Add here commands to compile the indep part of the package. 42 | #$(MAKE) doc 43 | touch $@ 44 | 45 | clean: config 46 | dh_testdir 47 | dh_testroot 48 | rm -f build-arch-stamp build-indep-stamp configure-stamp 49 | 50 | # Add here commands to clean up after the build process. 51 | $(MAKE) clean 52 | 53 | dh_clean 54 | 55 | install: install-indep install-arch 56 | install-indep: 57 | dh_testdir 58 | dh_testroot 59 | dh_clean -k -i 60 | dh_installdirs -i 61 | 62 | # Add here commands to install the indep part of the package into 63 | # debian/-doc. 64 | #INSTALLDOC# 65 | # $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install 66 | dh_install -i 67 | 68 | install-arch: 69 | dh_testdir 70 | dh_testroot 71 | dh_clean -k -s 72 | dh_installdirs -s 73 | 74 | # Add here commands to install the arch part of the package into 75 | # debian/{package}. 76 | mkdir -p debian/liba53/usr/lib 77 | mkdir -p debian/liba53/usr/include 78 | $(MAKE) DESTDIR=$(CURDIR)/debian/liba53 install 79 | 80 | dh_install -s 81 | 82 | # Must not depend on anything. This is to be called by 83 | # binary-arch/binary-indep 84 | # in another 'make' thread. 85 | binary-common: 86 | dh_testdir 87 | dh_testroot 88 | dh_installchangelogs ChangeLog 89 | dh_installdocs 90 | # dh_installexamples 91 | # dh_installmenu 92 | # dh_installdebconf 93 | dh_installlogrotate 94 | # dh_installemacsen 95 | # dh_installpam 96 | # dh_installmime 97 | # dh_python 98 | dh_installinit 99 | # dh_installcron 100 | # dh_installinfo 101 | dh_installman 102 | dh_link 103 | # dh_strip 104 | dh_compress 105 | dh_fixperms 106 | # dh_perl 107 | dh_makeshlibs 108 | dh_installdeb 109 | dh_shlibdeps 110 | dh_gencontrol 111 | dh_md5sums 112 | dh_builddeb 113 | # Build architecture independant packages using the common target. 114 | binary-indep: build-indep install-indep 115 | $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common 116 | 117 | # Build architecture dependant packages using the common target. 118 | binary-arch: build-arch install-arch 119 | $(MAKE) -f debian/rules DH_OPTIONS=-s binary-common 120 | 121 | binary: binary-arch binary-indep 122 | .PHONY: build clean binary-indep binary-arch binary install install-indep install-arch config 123 | 124 | -------------------------------------------------------------------------------- /gea.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gea.c 3 | * 4 | * Full reimplementation of GEA3 5 | * 6 | * Copyright (C) 2013 Max 7 | * 8 | * All Rights Reserved 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License along 21 | * with this program; if not, write to the Free Software Foundation, Inc., 22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 | */ 24 | #include 25 | 26 | #include "bits.h" 27 | #include "gprs_cipher.h" 28 | #include "kasumi.h" 29 | 30 | 31 | int osmo_gea4(uint8_t *out, uint16_t len, uint8_t * kc, uint32_t iv, enum gprs_cipher_direction direction) { 32 | _kasumi_kgcore(0xFF, 0, iv, direction, kc, out, len * 8); 33 | 34 | return 0; 35 | } 36 | 37 | int osmo_gea3(uint8_t *out, uint16_t len, uint64_t kc, uint32_t iv, enum gprs_cipher_direction direction) { 38 | uint8_t ck[16]; 39 | osmo_64pack2pbit(kc, ck); 40 | osmo_64pack2pbit(kc, ck + 8); 41 | 42 | // _kasumi_kgcore(0xFF, 0, iv, direction, ck, out, len * 8); 43 | 44 | return osmo_gea4(out, len, ck, iv, direction); 45 | } 46 | -------------------------------------------------------------------------------- /gea.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GEA3 header 3 | * 4 | * See gea.c for details 5 | */ 6 | 7 | #ifndef __GEA_H__ 8 | #define __GEA_H__ 9 | 10 | #include 11 | 12 | #include "gprs_cipher.h" 13 | 14 | /* 15 | * Performs the GEA3 algorithm (used in GPRS) 16 | * out : uint8_t [] 17 | * len : uint16_t 18 | * kc : uint64_t 19 | * iv : uint32_t 20 | * direct: 0 or 1 21 | */ 22 | 23 | int osmo_gea3(uint8_t *out, uint16_t len, uint64_t kc, uint32_t iv, enum gprs_cipher_direction direct); 24 | 25 | int osmo_gea4(uint8_t *out, uint16_t len, uint8_t * kc, uint32_t iv, enum gprs_cipher_direction direct); 26 | 27 | #endif /* __GEA_H__ */ 28 | 29 | -------------------------------------------------------------------------------- /gea_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "bits.h" 8 | #include "utils.h" 9 | #include "gprs_cipher.h" 10 | #include "gea.h" 11 | 12 | void print_check(char * res, uint8_t * out, uint16_t len) { 13 | uint8_t buf[len]; 14 | osmo_hexparse(res, buf, len); 15 | if (0 != memcmp(buf, out, len)) { 16 | printf("FAIL:\n"); 17 | printf("OUT: %s\n", osmo_hexdump_nospc(out, len)); 18 | printf("EXP: %s\n", osmo_hexdump_nospc(buf, len)); 19 | } 20 | else printf("OK\n"); 21 | } 22 | 23 | void test_gea3(uint64_t kc, uint32_t iv, int dir, uint16_t len, char * res) { 24 | printf("%d: %d -> 0x%X ", len, dir, iv); 25 | uint8_t out[len]; 26 | osmo_gea3(out, len, kc, iv, dir); 27 | print_check(res, out, len); 28 | } 29 | 30 | void test_gea4(char * kc, uint32_t iv, int dir, uint16_t len, char * res) { 31 | printf("%d: %d -> 0x%X ", len, dir, iv); 32 | uint8_t out[len], ck[256]; 33 | osmo_hexparse(kc, ck, len); 34 | osmo_gea4(out, len, ck, iv, dir); 35 | print_check(res, out, len); 36 | } 37 | 38 | int main(int argc, char **argv) 39 | { 40 | // printf("GEA3 support: %d\n", gprs_cipher_supported(GPRS_ALGO_GEA3)); 41 | // printf("GEA4 support: %d\n", gprs_cipher_supported(GPRS_ALGO_GEA4)); 42 | // test vectors according to 3GPP TS 55.217 and TS 55.218 43 | test_gea3(0x2BD6459F82C5BC00LL, 0x8E9421A3, 0, 59, "5F359709DE950D0105B17B6C90194280F880B48DCCDC2AFEED415DBEF4354EEBB21D073CCBBFB2D706BD7AFFD371FC96E3970D143DCB2624054826"); 44 | test_gea3(0x952C49104881FF48LL, 0x5064DB71, 0, 59, "FDC03D738C8E14FF0320E59AAF75760799E9DA78DD8F888471C4AEAAC1849633A26CD84F459D265B83D7D9B9A0B1E54F4D75E331640DF19E0DB0E0"); 45 | test_gea3(0xEFA8B2229E720C2ALL, 0x4BDBD5E5, 1, 59, "4718A2ADFC90590949DDADAB406EC3B925F1AF1214673909DAAB96BB4C18B1374BB1E99445A81CC856E47C6E49E9DBB9873D0831B2175CA1E109BA"); 46 | test_gea3(0x3451F23A43BD2C87LL, 0x893FE14F, 0, 59, "B46B1E284E3F8B63B86D9DF0915CFCEDDF2F061895BF9F82BF2593AE4847E94A4626C393CF8941CE15EA7812690D8415B88C5730FE1F5D410E16A2"); 47 | test_gea3(0xCAA2639BE82435CFLL, 0x8FE17885, 1, 59, "9FEFAF155A26CF35603E727CDAA87BA067FD84FF98A50B7FF0EC8E95A0FB70E79CB93DEE2B7E9AB59D050E1262401571F349C68229DDF0DECC4E85"); 48 | test_gea3(0x1ACA8B448B767B39LL, 0x4F7BC3B5, 0, 59, "514F6C3A3B5A55CA190092F7BB6E80EF3EDB738FCDCE2FF90BB387DDE75BBC32A04A67B898A3DFB8198FFFC37D437CF69E7F9C13B51A868720E750"); 49 | test_gea4("D3C5D592327FB11C4035C6680AF8C6D1", 0x0A3A59B4, 0, 51, "6E217CE41EBEFB5EC8094C15974290065E42BABC9AE35654A53085CE68DFA4426A2FF0AD4AF3341006A3F84B7613ACB4FBDC34"); 50 | test_gea4("3D43C388C9581E337FF1F97EB5C1F85E", 0x48571AB9, 0, 59, "FC7314EF00A63ED0116F236C5D25C54EEC56A5B71F9F18B4D7941F84E422ACBDE5EEA9A204679002D14F312F3DEE2A1AC917C3FBDC3696143C0F5D"); 51 | test_gea4("A4496A64DF4F399F3B4506814A3E07A1", 0xEB04ADE2, 1, 59, "2AEB5970FB06B718027D048488AAF24FB3B74EA4A6B1242FF85B108FF816A303C72757D9AAD862B835D1D287DBC141D0A28D79D87BB137CD1198CD"); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /gea_test.ok: -------------------------------------------------------------------------------- 1 | 59: 0 -> 0x8E9421A3 OK 2 | 59: 0 -> 0x5064DB71 OK 3 | 59: 1 -> 0x4BDBD5E5 OK 4 | 59: 0 -> 0x893FE14F OK 5 | 59: 1 -> 0x8FE17885 OK 6 | 59: 0 -> 0x4F7BC3B5 OK 7 | 51: 0 -> 0xA3A59B4 OK 8 | 59: 0 -> 0x48571AB9 OK 9 | 59: 1 -> 0xEB04ADE2 OK 10 | -------------------------------------------------------------------------------- /gprs_cipher.h: -------------------------------------------------------------------------------- 1 | #ifndef _GPRS_CIPHER_H 2 | #define _GPRS_CIPHER_H 3 | 4 | #include "linuxlist.h" 5 | 6 | #define GSM0464_CIPH_MAX_BLOCK 1523 7 | 8 | enum gprs_ciph_algo { 9 | GPRS_ALGO_GEA0, 10 | GPRS_ALGO_GEA1, 11 | GPRS_ALGO_GEA2, 12 | GPRS_ALGO_GEA3, 13 | GPRS_ALGO_GEA4, 14 | _GPRS_ALGO_NUM 15 | }; 16 | 17 | enum gprs_cipher_direction { 18 | GPRS_CIPH_MS2SGSN, 19 | GPRS_CIPH_SGSN2MS, 20 | }; 21 | 22 | /* An implementation of a GPRS cipher */ 23 | struct gprs_cipher_impl { 24 | struct llist_head list; 25 | enum gprs_ciph_algo algo; 26 | const char *name; 27 | unsigned int priority; 28 | 29 | /* As specified in 04.64 Annex A. Uses Kc, IV and direction 30 | * to generate the 1523 bytes cipher stream that need to be 31 | * XORed wit the plaintext for encrypt / ciphertext for decrypt */ 32 | int (*run)(uint8_t *out, uint16_t len, uint64_t kc, uint32_t iv, 33 | enum gprs_cipher_direction direction); 34 | }; 35 | 36 | /* register a cipher with the core (from a plugin) */ 37 | int gprs_cipher_register(struct gprs_cipher_impl *ciph); 38 | 39 | /* load all available GPRS cipher plugins */ 40 | int gprs_cipher_load(const char *path); 41 | 42 | /* function to be called by core code */ 43 | int gprs_cipher_run(uint8_t *out, uint16_t len, enum gprs_ciph_algo algo, 44 | uint64_t kc, uint32_t iv, enum gprs_cipher_direction dir); 45 | 46 | /* Do we have an implementation for this cipher? */ 47 | int gprs_cipher_supported(enum gprs_ciph_algo algo); 48 | 49 | /* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */ 50 | uint32_t gprs_cipher_gen_input_ui(uint32_t iov_ui, uint8_t sapi, uint32_t lfn, uint32_t oc); 51 | 52 | /* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */ 53 | uint32_t gprs_cipher_gen_input_i(uint32_t iov_i, uint32_t lfn, uint32_t oc); 54 | 55 | #endif /* _GPRS_CIPHER_H */ 56 | -------------------------------------------------------------------------------- /ifc.cpp: -------------------------------------------------------------------------------- 1 | #include "a53.h" 2 | #include "a5.h" 3 | #include 4 | 5 | void A53_GSM( u8 *key, int klen, int count, u8 *block1, u8 *block2 ) 6 | { 7 | ubit_t dl[120]; 8 | ubit_t ul[120]; 9 | static bool first = true; 10 | if (first) { 11 | printf("public A5/3\n"); 12 | first = false; 13 | } 14 | osmo_a5_3(key, (uint32_t)count, dl, ul); 15 | for (int i = 0; i < 15; i++) { 16 | unsigned char acc1 = 0; 17 | unsigned char acc2 = 0; 18 | for (int j = 0; j < 8; j++) { 19 | acc1 |= (dl[i*8+j] & 1) << (7-j); 20 | acc2 |= (ul[i*8+j] & 1) << (7-j); 21 | } 22 | block1[i] = acc1; 23 | block2[i] = acc2; 24 | } 25 | block1[14] &= 0xC0; 26 | block2[14] &= 0xC0; 27 | } 28 | -------------------------------------------------------------------------------- /kasumi.c: -------------------------------------------------------------------------------- 1 | /* Kasumi cipher and KGcore functions */ 2 | 3 | /* (C) 2013 by Max 4 | * 5 | * All Rights Reserved 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License along 18 | * with this program; if not, write to the Free Software Foundation, Inc., 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | */ 22 | 23 | #include 24 | #include "bits.h" 25 | #include "kasumi.h" 26 | 27 | static uint16_t 28 | _kasumi_FI(uint16_t I, uint16_t skey) 29 | { 30 | static uint16_t S7[] = { 31 | 54, 50, 62, 56, 22, 34, 94, 96, 38, 6, 63, 93, 2, 18, 123, 33, 32 | 55, 113, 39, 114, 21, 67, 65, 12, 47, 73, 46, 27, 25, 111, 124, 81, 33 | 53, 9, 121, 79, 52, 60, 58, 48, 101, 127, 40, 120, 104, 70, 71, 43, 34 | 20, 122, 72, 61, 23, 109, 13, 100, 77, 1, 16, 7, 82, 10, 105, 98, 35 | 117, 116, 76, 11, 89, 106, 0,125,118, 99, 86, 69, 30, 57, 126, 87, 36 | 112, 51, 17, 5, 95, 14, 90, 84, 91, 8, 35,103, 32, 97, 28, 66, 37 | 102, 31, 26, 45, 75, 4, 85, 92, 37, 74, 80, 49, 68, 29, 115, 44, 38 | 64, 107, 108, 24, 110, 83, 36, 78, 42, 19, 15, 41, 88, 119, 59, 3 39 | }; 40 | static uint16_t S9[] = { 41 | 167, 239, 161, 379, 391, 334, 9, 338, 38, 226, 48, 358, 452, 385, 90, 397, 42 | 183, 253, 147, 331, 415, 340, 51, 362, 306, 500, 262, 82, 216, 159, 356, 177, 43 | 175, 241, 489, 37, 206, 17, 0, 333, 44, 254, 378, 58, 143, 220, 81, 400, 44 | 95, 3, 315, 245, 54, 235, 218, 405, 472, 264, 172, 494, 371, 290, 399, 76, 45 | 165, 197, 395, 121, 257, 480, 423, 212, 240, 28, 462, 176, 406, 507, 288, 223, 46 | 501, 407, 249, 265, 89, 186, 221, 428,164, 74, 440, 196, 458, 421, 350, 163, 47 | 232, 158, 134, 354, 13, 250, 491, 142,191, 69, 193, 425, 152, 227, 366, 135, 48 | 344, 300, 276, 242, 437, 320, 113, 278, 11, 243, 87, 317, 36, 93, 496, 27, 49 | 487, 446, 482, 41, 68, 156, 457, 131, 326, 403, 339, 20, 39, 115, 442, 124, 50 | 475, 384, 508, 53, 112, 170, 479, 151, 126, 169, 73, 268, 279, 321, 168, 364, 51 | 363, 292, 46, 499, 393, 327, 324, 24, 456, 267, 157, 460, 488, 426, 309, 229, 52 | 439, 506, 208, 271, 349, 401, 434, 236, 16, 209, 359, 52, 56, 120, 199, 277, 53 | 465, 416, 252, 287, 246, 6, 83, 305, 420, 345, 153,502, 65, 61, 244, 282, 54 | 173, 222, 418, 67, 386, 368, 261, 101, 476, 291, 195,430, 49, 79, 166, 330, 55 | 280, 383, 373, 128, 382, 408, 155, 495, 367, 388, 274, 107, 459, 417, 62, 454, 56 | 132, 225, 203, 316, 234, 14, 301, 91, 503, 286, 424, 211, 347, 307, 140, 374, 57 | 35, 103, 125, 427, 19, 214, 453, 146, 498, 314, 444, 230, 256, 329, 198, 285, 58 | 50, 116, 78, 410, 10, 205, 510, 171, 231, 45, 139, 467, 29, 86, 505, 32, 59 | 72, 26, 342, 150, 313, 490, 431, 238, 411, 325, 149, 473, 40, 119, 174, 355, 60 | 185, 233, 389, 71, 448, 273, 372, 55, 110, 178, 322, 12, 469, 392, 369, 190, 61 | 1, 109, 375, 137, 181, 88, 75, 308, 260, 484, 98, 272, 370, 275, 412, 111, 62 | 336, 318, 4, 504, 492, 259, 304, 77, 337, 435, 21, 357, 303, 332, 483, 18, 63 | 47, 85, 25, 497, 474, 289, 100, 269, 296, 478, 270, 106, 31, 104, 433, 84, 64 | 414, 486, 394, 96, 99, 154, 511, 148, 413, 361, 409, 255, 162, 215, 302, 201, 65 | 266, 351, 343, 144, 441, 365, 108, 298, 251, 34, 182, 509, 138, 210, 335, 133, 66 | 311, 352, 328, 141, 396, 346, 123, 319, 450, 281, 429, 228, 443, 481, 92, 404, 67 | 485, 422, 248, 297, 23, 213, 130, 466, 22, 217, 283, 70, 294, 360, 419, 127, 68 | 312, 377, 7, 468, 194, 2, 117, 295, 463, 258, 224, 447, 247, 187, 80, 398, 69 | 284, 353, 105, 390, 299, 471, 470, 184, 57, 200, 348, 63, 204, 188, 33, 451, 70 | 97, 30, 310, 219, 94, 160, 129, 493, 64, 179, 263, 102, 189, 207, 114, 402, 71 | 438, 477, 387, 122, 192, 42, 381, 5, 145, 118, 180, 449, 293, 323, 136, 380, 72 | 43, 66, 60, 455, 341, 445, 202, 432, 8, 237, 15, 376, 436, 464, 59, 461 73 | }; 74 | uint16_t L, R; 75 | 76 | /* Split 16 bit input into two unequal halves: 9 and 7 bits, same for subkey */ 77 | L = I >> 7; /* take 9 bits */ 78 | R = I & 0x7F; /* take 7 bits */ 79 | 80 | L = S9[L] ^ R; 81 | R = S7[R] ^ (L & 0x7F); 82 | 83 | L ^= (skey & 0x1FF); 84 | R ^= (skey >> 9); 85 | 86 | L = S9[L] ^ R; 87 | R = S7[R] ^ (L & 0x7F); 88 | 89 | return (R << 9) + L; 90 | } 91 | 92 | static uint32_t 93 | _kasumi_FO(uint32_t I, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3, unsigned i) 94 | { 95 | uint16_t L = I >> 16, R = I; /* Split 32 bit input into Left and Right parts */ 96 | 97 | L ^= KOi1[i]; 98 | L = _kasumi_FI(L, KIi1[i]); 99 | L ^= R; 100 | 101 | R ^= KOi2[i]; 102 | R = _kasumi_FI(R, KIi2[i]); 103 | R ^= L; 104 | 105 | L ^= KOi3[i]; 106 | L = _kasumi_FI(L, KIi3[i]); 107 | L ^= R; 108 | 109 | return (((uint32_t)R) << 16) + L; 110 | } 111 | 112 | static uint32_t 113 | _kasumi_FL(uint32_t I, uint16_t *KLi1, uint16_t *KLi2, unsigned i) 114 | { 115 | uint16_t L = I >> 16, R = I, tmp; /* Split 32 bit input into Left and Right parts */ 116 | 117 | tmp = L & KLi1[i]; 118 | R ^= rol16(tmp, 1); 119 | 120 | tmp = R | KLi2[i]; 121 | L ^= rol16(tmp, 1); 122 | 123 | return (((uint32_t)L) << 16) + R; 124 | } 125 | 126 | uint64_t 127 | _kasumi(uint64_t P, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3) 128 | { 129 | uint32_t i, L = P >> 32, R = P; /* Split 64 bit input into Left and Right parts */ 130 | 131 | for (i = 0; i < 8; i++) 132 | { 133 | R ^= _kasumi_FO(_kasumi_FL(L, KLi1, KLi2, i), KOi1, KOi2, KOi3, KIi1, KIi2, KIi3, i); /* odd round */ 134 | i++; 135 | L ^= _kasumi_FL(_kasumi_FO(R, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3, i), KLi1, KLi2, i); /* even round */ 136 | } 137 | return (((uint64_t)L) << 32) + R; /* Concatenate Left and Right 32 bits into 64 bit ciphertext */ 138 | } 139 | 140 | /*! \brief Expand key into set of subkeys 141 | * \param[in] key (128 bits) as array of bytes 142 | * \param[out] arrays of round-specific subkeys - see TS 135 202 for details 143 | */ 144 | void 145 | _kasumi_key_expand(const uint8_t *key, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3) 146 | { 147 | uint16_t i, C[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF, 0xFEDC, 0xBA98, 0x7654, 0x3210 }; 148 | 149 | for (i = 0; i < 8; i++) /* Work with 16 bit subkeys and create prime subkeys */ 150 | { 151 | C[i] ^= osmo_get2bytes(key + i * 2); 152 | } 153 | /* C[] now stores K-prime[] */ 154 | for (i = 0; i < 8; i++) /* Create round-specific subkeys */ 155 | { 156 | KLi1[i] = rol16(osmo_get2bytes(key + i * 2), 1); 157 | KLi2[i] = C[(i + 2) & 0x7]; 158 | 159 | KOi1[i] = rol16(osmo_get2bytes(key + ((2 * (i + 1)) & 0xE)), 5); 160 | KOi2[i] = rol16(osmo_get2bytes(key + ((2 * (i + 5)) & 0xE)), 8); 161 | KOi3[i] = rol16(osmo_get2bytes(key + ((2 * (i + 6)) & 0xE)), 13); 162 | 163 | KIi1[i] = C[(i + 4) & 0x7]; 164 | KIi2[i] = C[(i + 3) & 0x7]; 165 | KIi3[i] = C[(i + 7) & 0x7]; 166 | } 167 | } 168 | 169 | void 170 | _kasumi_kgcore(uint8_t CA, uint8_t cb, uint32_t cc, uint8_t cd, const uint8_t *ck, uint8_t *co, uint16_t cl) 171 | { 172 | uint16_t KLi1[8], KLi2[8], KOi1[8], KOi2[8], KOi3[8], KIi1[8], KIi2[8], KIi3[8], i; 173 | uint64_t A = ((uint64_t)cc) << 32, BLK = 0, _ca = ((uint64_t)CA << 16) ; 174 | A |= _ca; 175 | _ca = (uint64_t)((cb << 3) | (cd << 2)) << 24; 176 | A |= _ca; 177 | /* Register loading complete: see TR 55.919 8.2 and TS 55.216 3.2 */ 178 | 179 | uint8_t ck_km[16]; 180 | for (i = 0; i < 16; i++) ck_km[i] = ck[i] ^ 0x55; /* Modified key established */ 181 | 182 | /* preliminary round with modified key */ 183 | _kasumi_key_expand(ck_km, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3); 184 | A = _kasumi(A, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3); 185 | 186 | /* Run Kasumi in OFB to obtain enough data for gamma. */ 187 | _kasumi_key_expand(ck, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3); 188 | for (i = 0; i < cl / 64 + 1; i++) /* i is a block counter */ 189 | { 190 | BLK = _kasumi(A ^ i ^ BLK, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3); 191 | osmo_64pack2pbit(BLK, co + (i * 8)); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /kasumi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * KASUMI header 3 | * 4 | * See kasumi.c for details 5 | */ 6 | 7 | #ifndef __KASUMI_H__ 8 | #define __KASUMI_H__ 9 | 10 | #include 11 | 12 | /* 13 | * Single iteration of KASUMI cipher 14 | */ 15 | uint64_t _kasumi(uint64_t P, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3); 16 | 17 | /* 18 | * Implementation of the KGCORE algorithm (used by A5/3, A5/4, GEA3, GEA4 and ECSD) 19 | * 20 | * CA : uint8_t 21 | * cb : uint8_t 22 | * cc : uint32_t 23 | * cd : uint8_t 24 | * ck : uint8_t [8] 25 | * co : uint8_t [output, cl-dependent] 26 | * cl : uint16_t 27 | */ 28 | void _kasumi_kgcore(uint8_t CA, uint8_t cb, uint32_t cc, uint8_t cd, const uint8_t *ck, uint8_t *co, uint16_t cl); 29 | 30 | /*! \brief Expand key into set of subkeys 31 | * \param[in] key (128 bits) as array of bytes 32 | * \param[out] arrays of round-specific subkeys - see TS 135 202 for details 33 | */ 34 | void _kasumi_key_expand(const uint8_t *key, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3); 35 | 36 | #endif /* __KASUMI_H__ */ 37 | -------------------------------------------------------------------------------- /kasumi_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "bits.h" 8 | #include "utils.h" 9 | #include "kasumi.h" // for testing internal A5/3 functions 10 | 11 | 12 | inline int _compare_mem(uint8_t * x, uint8_t * y, size_t len) { 13 | if (0 != memcmp(x, y, len)) { 14 | printf ("X: %s\t", osmo_hexdump_nospc(x, len)); 15 | printf ("Y: %s\n", osmo_hexdump_nospc(y, len)); 16 | return 0; 17 | } 18 | return 1; 19 | } 20 | 21 | inline static void test_expansion(uint8_t * test_key, uint16_t * _KLi1, uint16_t * _KLi2, uint16_t * _KOi1, uint16_t * _KOi2, uint16_t * _KOi3, uint16_t * _KIi1, uint16_t * _KIi2, uint16_t * _KIi3, uint16_t * _KLi1_r, uint16_t * _KLi2_r, uint16_t * _KOi1_r, uint16_t * _KOi2_r, uint16_t * _KOi3_r, uint16_t * _KIi1_r, uint16_t * _KIi2_r, uint16_t * _KIi3_r) 22 | { 23 | _kasumi_key_expand(test_key, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3); 24 | int passed = 1; 25 | passed = _compare_mem((uint8_t *)_KLi1, (uint8_t *)_KLi1_r, 16); 26 | passed = _compare_mem((uint8_t *)_KLi2, (uint8_t *)_KLi2_r, 16); 27 | passed = _compare_mem((uint8_t *)_KOi1, (uint8_t *)_KOi1_r, 16); 28 | passed = _compare_mem((uint8_t *)_KOi2, (uint8_t *)_KOi2_r, 16); 29 | passed = _compare_mem((uint8_t *)_KOi3, (uint8_t *)_KOi3_r, 16); 30 | passed = _compare_mem((uint8_t *)_KIi1, (uint8_t *)_KIi1_r, 16); 31 | passed = _compare_mem((uint8_t *)_KIi2, (uint8_t *)_KIi2_r, 16); 32 | passed = _compare_mem((uint8_t *)_KIi3, (uint8_t *)_KIi3_r, 16); 33 | if (passed) printf(" OK. "); else printf("FAILED!"); 34 | } 35 | 36 | int main(int argc, char **argv) 37 | { 38 | uint16_t _KLi1[8], _KLi2[8], _KOi1[8], _KOi2[8], _KOi3[8], _KIi1[8], _KIi2[8], _KIi3[8], _KLi1_r[8], _KLi2_r[8], _KOi1_r[8], _KOi2_r[8], _KOi3_r[8], _KIi1_r[8], _KIi2_r[8], _KIi3_r[8]; 39 | 40 | printf("testing KASUMI key expansion and encryption (ETSI TS 135 203):\n"); 41 | printf("KASUMI Test Set 1..."); 42 | 43 | uint8_t _test_key1[] = {0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48}; 44 | _KLi1_r[0] = 0x57AC; _KLi1_r[1] = 0x8B3E; _KLi1_r[2] = 0x058B; _KLi1_r[3] = 0x6601; _KLi1_r[4] = 0x2A59; _KLi1_r[5] = 0x9220; _KLi1_r[6] = 0x9102; _KLi1_r[7] = 0xFE91; 45 | _KLi2_r[0] = 0x0B6E; _KLi2_r[1] = 0x7EEF; _KLi2_r[2] = 0x6BF0; _KLi2_r[3] = 0xF388; _KLi2_r[4] = 0x3ED5; _KLi2_r[5] = 0xCD58; _KLi2_r[6] = 0x2AF5; _KLi2_r[7] = 0x00F8; 46 | _KOi1_r[0] = 0xB3E8; _KOi1_r[1] = 0x58B0; _KOi1_r[2] = 0x6016; _KOi1_r[3] = 0xA592; _KOi1_r[4] = 0x2209; _KOi1_r[5] = 0x1029; _KOi1_r[6] = 0xE91F; _KOi1_r[7] = 0x7AC5; 47 | _KOi2_r[0] = 0x1049; _KOi2_r[1] = 0x8148; _KOi2_r[2] = 0x48FF; _KOi2_r[3] = 0xD62B; _KOi2_r[4] = 0x9F45; _KOi2_r[5] = 0xC582; _KOi2_r[6] = 0x00B3; _KOi2_r[7] = 0x2C95; 48 | _KOi3_r[0] = 0x2910; _KOi3_r[1] = 0x1FE9; _KOi3_r[2] = 0xC57A; _KOi3_r[3] = 0xE8B3; _KOi3_r[4] = 0xB058; _KOi3_r[5] = 0x1660; _KOi3_r[6] = 0x92A5; _KOi3_r[7] = 0x0922; 49 | _KIi1_r[0] = 0x6BF0; _KIi1_r[1] = 0xF388; _KIi1_r[2] = 0x3ED5; _KIi1_r[3] = 0xCD58; _KIi1_r[4] = 0x2AF5; _KIi1_r[5] = 0x00F8; _KIi1_r[6] = 0x0B6E; _KIi1_r[7] = 0x7EEF; 50 | _KIi2_r[0] = 0x7EEF; _KIi2_r[1] = 0x6BF0; _KIi2_r[2] = 0xF388; _KIi2_r[3] = 0x3ED5; _KIi2_r[4] = 0xCD58; _KIi2_r[5] = 0x2AF5; _KIi2_r[6] = 0x00F8; _KIi2_r[7] = 0x0B6E; 51 | _KIi3_r[0] = 0xCD58; _KIi3_r[1] = 0x2AF5; _KIi3_r[2] = 0x00F8; _KIi3_r[3] = 0x0B6E; _KIi3_r[4] = 0x7EEF; _KIi3_r[5] = 0x6BF0; _KIi3_r[6] = 0xF388; _KIi3_r[7] = 0x3ED5; 52 | test_expansion(_test_key1, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3, _KLi1_r, _KLi2_r, _KOi1_r, _KOi2_r, _KOi3_r, _KIi1_r, _KIi2_r, _KIi3_r); 53 | 54 | if (0xDF1F9B251C0BF45FLL == _kasumi(0xEA024714AD5C4D84LL, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3)) 55 | printf("OK."); else printf("FAILED!"); 56 | 57 | printf("\nKASUMI Test Set 2..."); 58 | 59 | uint8_t _test_key2[] = {0x8C, 0xE3, 0x3E, 0x2C, 0xC3, 0xC0, 0xB5, 0xFC, 0x1F, 0x3D, 0xE8, 0xA6, 0xDC, 0x66, 0xB1, 0xF3}; 60 | _KLi1_r[0] = 0x19C7; _KLi1_r[1] = 0x7C58; _KLi1_r[2] = 0x8781; _KLi1_r[3] = 0x6BF9; _KLi1_r[4] = 0x3E7A; _KLi1_r[5] = 0xD14D; _KLi1_r[6] = 0xB8CD; _KLi1_r[7] = 0x63E7; 61 | _KLi2_r[0] = 0x4A6B; _KLi2_r[1] = 0x7813; _KLi2_r[2] = 0xE1E1; _KLi2_r[3] = 0x523E; _KLi2_r[4] = 0xAA32; _KLi2_r[5] = 0x83E3; _KLi2_r[6] = 0x8DC0; _KLi2_r[7] = 0x7B4B; 62 | _KOi1_r[0] = 0xC587; _KOi1_r[1] = 0x7818; _KOi1_r[2] = 0xBF96; _KOi1_r[3] = 0xE7A3; _KOi1_r[4] = 0x14DD; _KOi1_r[5] = 0x8CDB; _KOi1_r[6] = 0x3E76; _KOi1_r[7] = 0x9C71; 63 | _KOi2_r[0] = 0xA6E8; _KOi2_r[1] = 0x66DC; _KOi2_r[2] = 0xF3B1; _KOi2_r[3] = 0xE38C; _KOi2_r[4] = 0x2C3E; _KOi2_r[5] = 0xC0C3; _KOi2_r[6] = 0xFCB5; _KOi2_r[7] = 0x3D1F; 64 | _KOi3_r[0] = 0xDB8C; _KOi3_r[1] = 0x763E; _KOi3_r[2] = 0x719C; _KOi3_r[3] = 0x87C5; _KOi3_r[4] = 0x1878; _KOi3_r[5] = 0x96BF; _KOi3_r[6] = 0xA3E7; _KOi3_r[7] = 0xDD14; 65 | _KIi1_r[0] = 0xE1E1; _KIi1_r[1] = 0x523E; _KIi1_r[2] = 0xAA32; _KIi1_r[3] = 0x83E3; _KIi1_r[4] = 0x8DC0; _KIi1_r[5] = 0x7B4B; _KIi1_r[6] = 0x4A6B; _KIi1_r[7] = 0x7813; 66 | _KIi2_r[0] = 0x7813; _KIi2_r[1] = 0xE1E1; _KIi2_r[2] = 0x523E; _KIi2_r[3] = 0xAA32; _KIi2_r[4] = 0x83E3; _KIi2_r[5] = 0x8DC0; _KIi2_r[6] = 0x7B4B; _KIi2_r[7] = 0x4A6B; 67 | _KIi3_r[0] = 0x83E3; _KIi3_r[1] = 0x8DC0; _KIi3_r[2] = 0x7B4B; _KIi3_r[3] = 0x4A6B; _KIi3_r[4] = 0x7813; _KIi3_r[5] = 0xE1E1; _KIi3_r[6] = 0x523E; _KIi3_r[7] = 0xAA32; 68 | test_expansion(_test_key2, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3, _KLi1_r, _KLi2_r, _KOi1_r, _KOi2_r, _KOi3_r, _KIi1_r, _KIi2_r, _KIi3_r); 69 | 70 | if (0xDE551988CEB2F9B7LL == _kasumi(0xD3C5D592327FB11CLL, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3)) 71 | printf("OK."); else printf("FAILED!"); 72 | 73 | printf("\nKASUMI Test Set 3..."); 74 | 75 | uint8_t _test_key3[] = {0x40, 0x35, 0xC6, 0x68, 0x0A, 0xF8, 0xC6, 0xD1, 0xA8, 0xFF, 0x86, 0x67, 0xB1, 0x71, 0x40, 0x13}; 76 | _KLi1_r[0] = 0x806A; _KLi1_r[1] = 0x8CD1; _KLi1_r[2] = 0x15F0; _KLi1_r[3] = 0x8DA3; _KLi1_r[4] = 0x51FF; _KLi1_r[5] = 0x0CCF; _KLi1_r[6] = 0x62E3; _KLi1_r[7] = 0x8026; 77 | _KLi2_r[0] = 0x8353; _KLi2_r[1] = 0x0B3E; _KLi2_r[2] = 0x5623; _KLi2_r[3] = 0x3CFF; _KLi2_r[4] = 0xC725; _KLi2_r[5] = 0x7203; _KLi2_r[6] = 0x4116; _KLi2_r[7] = 0x830F; 78 | _KOi1_r[0] = 0xCD18; _KOi1_r[1] = 0x5F01; _KOi1_r[2] = 0xDA38; _KOi1_r[3] = 0x1FF5; _KOi1_r[4] = 0xCCF0; _KOi1_r[5] = 0x2E36; _KOi1_r[6] = 0x0268; _KOi1_r[7] = 0x06A8; 79 | _KOi2_r[0] = 0x6786; _KOi2_r[1] = 0x71B1; _KOi2_r[2] = 0x1340; _KOi2_r[3] = 0x3540; _KOi2_r[4] = 0x68C6; _KOi2_r[5] = 0xF80A; _KOi2_r[6] = 0xD1C6; _KOi2_r[7] = 0xFFA8; 80 | _KOi3_r[0] = 0x362E; _KOi3_r[1] = 0x6802; _KOi3_r[2] = 0xA806; _KOi3_r[3] = 0x18CD; _KOi3_r[4] = 0x015F; _KOi3_r[5] = 0x38DA; _KOi3_r[6] = 0xF51F; _KOi3_r[7] = 0xF0CC; 81 | _KIi1_r[0] = 0x5623; _KIi1_r[1] = 0x3CFF; _KIi1_r[2] = 0xC725; _KIi1_r[3] = 0x7203; _KIi1_r[4] = 0x4116; _KIi1_r[5] = 0x830F; _KIi1_r[6] = 0x8353; _KIi1_r[7] = 0x0B3E; 82 | _KIi2_r[0] = 0x0B3E; _KIi2_r[1] = 0x5623; _KIi2_r[2] = 0x3CFF; _KIi2_r[3] = 0xC725; _KIi2_r[4] = 0x7203; _KIi2_r[5] = 0x4116; _KIi2_r[6] = 0x830F; _KIi2_r[7] = 0x8353; 83 | _KIi3_r[0] = 0x7203; _KIi3_r[1] = 0x4116; _KIi3_r[2] = 0x830F; _KIi3_r[3] = 0x8353; _KIi3_r[4] = 0x0B3E; _KIi3_r[5] = 0x5623; _KIi3_r[6] = 0x3CFF; _KIi3_r[7] = 0xC725; 84 | test_expansion(_test_key3, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3, _KLi1_r, _KLi2_r, _KOi1_r, _KOi2_r, _KOi3_r, _KIi1_r, _KIi2_r, _KIi3_r); 85 | 86 | if (0x4592B0E78690F71BLL == _kasumi(0x62A540981BA6F9B7LL, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3)) 87 | printf("OK."); else printf("FAILED!"); 88 | 89 | printf("\nKASUMI Test Set 4..."); 90 | uint8_t _test_key4[] = {0x3A, 0x3B, 0x39, 0xB5, 0xC3, 0xF2, 0x37, 0x6D, 0x69, 0xF7, 0xD5, 0x46, 0xE5, 0xF8, 0x5D, 0x43}; 91 | uint64_t I4 = 0xCA49C1C75771AB0BLL, i; 92 | _kasumi_key_expand(_test_key4, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3); 93 | 94 | for (i = 0; i < 50; i++) 95 | I4 = _kasumi(I4, _KLi1, _KLi2, _KOi1, _KOi2, _KOi3, _KIi1, _KIi2, _KIi3); 96 | 97 | if (0x738BAD4C4A690802LL == I4) printf(" OK.\n"); else printf("FAILED!"); 98 | 99 | 100 | uint8_t gamma[32]; 101 | 102 | uint8_t _Key1[] = {0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xBC, 0x00, 0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xBC, 0x00}, 103 | _gamma1[] = {0x88, 0x9E, 0xEA, 0xAF, 0x9E, 0xD1, 0xBA, 0x1A, 0xBB, 0xD8, 0x43, 0x62, 0x32, 0xE4, 0x57, 0x28, 0xD0, 0x1A, 0xA8, 0x91, 0x33, 0xDA, 0x73, 0xC1, 0x1E, 0xAB, 0x68, 0xB7, 0xD8, 0x9B, 0xC8, 0x41}; 104 | _kasumi_kgcore(0xF, 0, 0x0024F20F, 0, _Key1, gamma, 228); 105 | printf ("KGCORE Test Set 1: %d\n", _compare_mem(gamma, _gamma1, 32)); 106 | 107 | uint8_t _Key2[] = {0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48, 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48}, 108 | _gamma2[] = {0xFB, 0x4D, 0x5F, 0xBC, 0xEE, 0x13, 0xA3, 0x33, 0x89, 0x28, 0x56, 0x86, 0xE9, 0xA5, 0xC9, 0x42, 0x40, 0xDE, 0x38, 0x15, 0x01, 0x15, 0xF1, 0x5F, 0x8D, 0x9D, 0x98, 0xB9, 0x1A, 0x94, 0xB2, 0x96}; 109 | _kasumi_kgcore(0xF, 0, 0x00061272, 0, _Key2, gamma, 228); 110 | printf ("KGCORE Test Set 2: %d\n", _compare_mem(gamma, _gamma2, 32)); 111 | 112 | uint8_t _Key3[] = {0xEF, 0xA8, 0xB2, 0x22, 0x9E, 0x72, 0x0C, 0x2A, 0xEF, 0xA8, 0xB2, 0x22, 0x9E, 0x72, 0x0C, 0x2A}, 113 | _gamma3[] = {0x0E, 0x40, 0x15, 0x75, 0x5A, 0x33, 0x64, 0x69, 0xC3, 0xDD, 0x86, 0x80, 0xE3, 0x03, 0x5B, 0xC4, 0x19, 0xA7, 0x8A, 0xD3, 0x86, 0x2C, 0x10, 0x90, 0xC6, 0x8A, 0x39, 0x1F, 0xE8, 0xA6, 0xAD, 0xEB}; 114 | _kasumi_kgcore(0xF, 0, 0x0033FD3F, 0, _Key3, gamma, 228); 115 | printf ("KGCORE Test Set 3: %d\n", _compare_mem(gamma, _gamma3, 32)); 116 | 117 | uint8_t _Key4[] = {0x5A, 0xCB, 0x1D, 0x64, 0x4C, 0x0D, 0x51, 0x20, 0x4E, 0xA5, 0x5A, 0xCB, 0x1D, 0x64, 0x4C, 0x0D}, 118 | _gamma4[] = {0xE0, 0x95, 0x30, 0x6A, 0xD5, 0x08, 0x6E, 0x2E, 0xAC, 0x7F, 0x31, 0x07, 0xDE, 0x4F, 0xA2, 0x2D, 0xC1, 0xDF, 0xC9, 0x7D, 0x5B, 0xC5, 0x66, 0x1D, 0xD6, 0x09, 0x6F, 0x47, 0x6A, 0xED, 0xC6, 0x4B}; 119 | _kasumi_kgcore(0xF, 0, 0x00156B26, 0, _Key4, gamma, 228); 120 | printf ("KGCORE Test Set 4: %d\n", _compare_mem(gamma, _gamma4, 32)); 121 | 122 | uint8_t _Key5[] = {0xD3, 0xC5, 0xD5, 0x92, 0x32, 0x7F, 0xB1, 0x1C, 0x40, 0x35, 0xC6, 0x68, 0x0A, 0xF8, 0xC6, 0xD1}, 123 | _gamma5[] = {0xDC, 0xE6, 0x43, 0x62, 0xAB, 0x5F, 0x89, 0xC1, 0x1E, 0xF0, 0xB3, 0x05, 0x16, 0x65, 0x70, 0xF4, 0x88, 0x9D, 0x55, 0x11, 0xE9, 0xE3, 0x57, 0x5D, 0x06, 0x2B, 0x5C, 0xED, 0x60, 0x39, 0x50, 0x6A}; 124 | _kasumi_kgcore(0xF, 0, 0x000A59B4, 0, _Key5, gamma, 228); 125 | printf ("KGCORE Test Set 5: %d\n", _compare_mem(gamma, _gamma5, 32)); 126 | 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /kasumi_test.ok: -------------------------------------------------------------------------------- 1 | testing KASUMI key expansion and encryption (ETSI TS 135 203): 2 | KASUMI Test Set 1... OK. OK. 3 | KASUMI Test Set 2... OK. OK. 4 | KASUMI Test Set 3... OK. OK. 5 | KASUMI Test Set 4... OK. 6 | KGCORE Test Set 1: 1 7 | KGCORE Test Set 2: 1 8 | KGCORE Test Set 3: 1 9 | KGCORE Test Set 4: 1 10 | KGCORE Test Set 5: 1 11 | -------------------------------------------------------------------------------- /linuxlist.h: -------------------------------------------------------------------------------- 1 | #ifndef _LINUX_LLIST_H 2 | #define _LINUX_LLIST_H 3 | 4 | #include 5 | 6 | #ifndef inline 7 | #define inline __inline__ 8 | #endif 9 | 10 | static inline void prefetch(__attribute__((unused)) const void *x) {;} 11 | 12 | /** 13 | * container_of - cast a member of a structure out to the containing structure 14 | * 15 | * @ptr: the pointer to the member. 16 | * @type: the type of the container struct this is embedded in. 17 | * @member: the name of the member within the struct. 18 | * 19 | */ 20 | #define container_of(ptr, type, member) ({ \ 21 | const typeof( ((type *)0)->member ) *__mptr = (typeof( ((type *)0)->member ) *)(ptr); \ 22 | (type *)( (char *)__mptr - offsetof(type, member) );}) 23 | 24 | 25 | /* 26 | * These are non-NULL pointers that will result in page faults 27 | * under normal circumstances, used to verify that nobody uses 28 | * non-initialized llist entries. 29 | */ 30 | #define LLIST_POISON1 ((void *) 0x00100100) 31 | #define LLIST_POISON2 ((void *) 0x00200200) 32 | 33 | /* 34 | * Simple doubly linked llist implementation. 35 | * 36 | * Some of the internal functions ("__xxx") are useful when 37 | * manipulating whole llists rather than single entries, as 38 | * sometimes we already know the next/prev entries and we can 39 | * generate better code by using them directly rather than 40 | * using the generic single-entry routines. 41 | */ 42 | 43 | struct llist_head { 44 | struct llist_head *next, *prev; 45 | }; 46 | 47 | #define LLIST_HEAD_INIT(name) { &(name), &(name) } 48 | 49 | #define LLIST_HEAD(name) \ 50 | struct llist_head name = LLIST_HEAD_INIT(name) 51 | 52 | #define INIT_LLIST_HEAD(ptr) do { \ 53 | (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 54 | } while (0) 55 | 56 | /* 57 | * Insert a new entry between two known consecutive entries. 58 | * 59 | * This is only for internal llist manipulation where we know 60 | * the prev/next entries already! 61 | */ 62 | static inline void __llist_add(struct llist_head *_new, 63 | struct llist_head *prev, 64 | struct llist_head *next) 65 | { 66 | next->prev = _new; 67 | _new->next = next; 68 | _new->prev = prev; 69 | prev->next = _new; 70 | } 71 | 72 | /** 73 | * llist_add - add a new entry 74 | * @new: new entry to be added 75 | * @head: llist head to add it after 76 | * 77 | * Insert a new entry after the specified head. 78 | * This is good for implementing stacks. 79 | */ 80 | static inline void llist_add(struct llist_head *_new, struct llist_head *head) 81 | { 82 | __llist_add(_new, head, head->next); 83 | } 84 | 85 | /** 86 | * llist_add_tail - add a new entry 87 | * @new: new entry to be added 88 | * @head: llist head to add it before 89 | * 90 | * Insert a new entry before the specified head. 91 | * This is useful for implementing queues. 92 | */ 93 | static inline void llist_add_tail(struct llist_head *_new, struct llist_head *head) 94 | { 95 | __llist_add(_new, head->prev, head); 96 | } 97 | 98 | /* 99 | * Delete a llist entry by making the prev/next entries 100 | * point to each other. 101 | * 102 | * This is only for internal llist manipulation where we know 103 | * the prev/next entries already! 104 | */ 105 | static inline void __llist_del(struct llist_head * prev, struct llist_head * next) 106 | { 107 | next->prev = prev; 108 | prev->next = next; 109 | } 110 | 111 | /** 112 | * llist_del - deletes entry from llist. 113 | * @entry: the element to delete from the llist. 114 | * Note: llist_empty on entry does not return true after this, the entry is 115 | * in an undefined state. 116 | */ 117 | static inline void llist_del(struct llist_head *entry) 118 | { 119 | __llist_del(entry->prev, entry->next); 120 | entry->next = (struct llist_head *)LLIST_POISON1; 121 | entry->prev = (struct llist_head *)LLIST_POISON2; 122 | } 123 | 124 | /** 125 | * llist_del_init - deletes entry from llist and reinitialize it. 126 | * @entry: the element to delete from the llist. 127 | */ 128 | static inline void llist_del_init(struct llist_head *entry) 129 | { 130 | __llist_del(entry->prev, entry->next); 131 | INIT_LLIST_HEAD(entry); 132 | } 133 | 134 | /** 135 | * llist_move - delete from one llist and add as another's head 136 | * @llist: the entry to move 137 | * @head: the head that will precede our entry 138 | */ 139 | static inline void llist_move(struct llist_head *llist, struct llist_head *head) 140 | { 141 | __llist_del(llist->prev, llist->next); 142 | llist_add(llist, head); 143 | } 144 | 145 | /** 146 | * llist_move_tail - delete from one llist and add as another's tail 147 | * @llist: the entry to move 148 | * @head: the head that will follow our entry 149 | */ 150 | static inline void llist_move_tail(struct llist_head *llist, 151 | struct llist_head *head) 152 | { 153 | __llist_del(llist->prev, llist->next); 154 | llist_add_tail(llist, head); 155 | } 156 | 157 | /** 158 | * llist_empty - tests whether a llist is empty 159 | * @head: the llist to test. 160 | */ 161 | static inline int llist_empty(const struct llist_head *head) 162 | { 163 | return head->next == head; 164 | } 165 | 166 | static inline void __llist_splice(struct llist_head *llist, 167 | struct llist_head *head) 168 | { 169 | struct llist_head *first = llist->next; 170 | struct llist_head *last = llist->prev; 171 | struct llist_head *at = head->next; 172 | 173 | first->prev = head; 174 | head->next = first; 175 | 176 | last->next = at; 177 | at->prev = last; 178 | } 179 | 180 | /** 181 | * llist_splice - join two llists 182 | * @llist: the new llist to add. 183 | * @head: the place to add it in the first llist. 184 | */ 185 | static inline void llist_splice(struct llist_head *llist, struct llist_head *head) 186 | { 187 | if (!llist_empty(llist)) 188 | __llist_splice(llist, head); 189 | } 190 | 191 | /** 192 | * llist_splice_init - join two llists and reinitialise the emptied llist. 193 | * @llist: the new llist to add. 194 | * @head: the place to add it in the first llist. 195 | * 196 | * The llist at @llist is reinitialised 197 | */ 198 | static inline void llist_splice_init(struct llist_head *llist, 199 | struct llist_head *head) 200 | { 201 | if (!llist_empty(llist)) { 202 | __llist_splice(llist, head); 203 | INIT_LLIST_HEAD(llist); 204 | } 205 | } 206 | 207 | /** 208 | * llist_entry - get the struct for this entry 209 | * @ptr: the &struct llist_head pointer. 210 | * @type: the type of the struct this is embedded in. 211 | * @member: the name of the llist_struct within the struct. 212 | */ 213 | #define llist_entry(ptr, type, member) \ 214 | container_of(ptr, type, member) 215 | 216 | /** 217 | * llist_for_each - iterate over a llist 218 | * @pos: the &struct llist_head to use as a loop counter. 219 | * @head: the head for your llist. 220 | */ 221 | #define llist_for_each(pos, head) \ 222 | for (pos = (head)->next, prefetch(pos->next); pos != (head); \ 223 | pos = pos->next, prefetch(pos->next)) 224 | 225 | /** 226 | * __llist_for_each - iterate over a llist 227 | * @pos: the &struct llist_head to use as a loop counter. 228 | * @head: the head for your llist. 229 | * 230 | * This variant differs from llist_for_each() in that it's the 231 | * simplest possible llist iteration code, no prefetching is done. 232 | * Use this for code that knows the llist to be very short (empty 233 | * or 1 entry) most of the time. 234 | */ 235 | #define __llist_for_each(pos, head) \ 236 | for (pos = (head)->next; pos != (head); pos = pos->next) 237 | 238 | /** 239 | * llist_for_each_prev - iterate over a llist backwards 240 | * @pos: the &struct llist_head to use as a loop counter. 241 | * @head: the head for your llist. 242 | */ 243 | #define llist_for_each_prev(pos, head) \ 244 | for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ 245 | pos = pos->prev, prefetch(pos->prev)) 246 | 247 | /** 248 | * llist_for_each_safe - iterate over a llist safe against removal of llist entry 249 | * @pos: the &struct llist_head to use as a loop counter. 250 | * @n: another &struct llist_head to use as temporary storage 251 | * @head: the head for your llist. 252 | */ 253 | #define llist_for_each_safe(pos, n, head) \ 254 | for (pos = (head)->next, n = pos->next; pos != (head); \ 255 | pos = n, n = pos->next) 256 | 257 | /** 258 | * llist_for_each_entry - iterate over llist of given type 259 | * @pos: the type * to use as a loop counter. 260 | * @head: the head for your llist. 261 | * @member: the name of the llist_struct within the struct. 262 | */ 263 | #define llist_for_each_entry(pos, head, member) \ 264 | for (pos = llist_entry((head)->next, typeof(*pos), member), \ 265 | prefetch(pos->member.next); \ 266 | &pos->member != (head); \ 267 | pos = llist_entry(pos->member.next, typeof(*pos), member), \ 268 | prefetch(pos->member.next)) 269 | 270 | /** 271 | * llist_for_each_entry_reverse - iterate backwards over llist of given type. 272 | * @pos: the type * to use as a loop counter. 273 | * @head: the head for your llist. 274 | * @member: the name of the llist_struct within the struct. 275 | */ 276 | #define llist_for_each_entry_reverse(pos, head, member) \ 277 | for (pos = llist_entry((head)->prev, typeof(*pos), member), \ 278 | prefetch(pos->member.prev); \ 279 | &pos->member != (head); \ 280 | pos = llist_entry(pos->member.prev, typeof(*pos), member), \ 281 | prefetch(pos->member.prev)) 282 | 283 | /** 284 | * llist_for_each_entry_continue - iterate over llist of given type 285 | * continuing after existing point 286 | * @pos: the type * to use as a loop counter. 287 | * @head: the head for your llist. 288 | * @member: the name of the llist_struct within the struct. 289 | */ 290 | #define llist_for_each_entry_continue(pos, head, member) \ 291 | for (pos = llist_entry(pos->member.next, typeof(*pos), member), \ 292 | prefetch(pos->member.next); \ 293 | &pos->member != (head); \ 294 | pos = llist_entry(pos->member.next, typeof(*pos), member), \ 295 | prefetch(pos->member.next)) 296 | 297 | /** 298 | * llist_for_each_entry_safe - iterate over llist of given type safe against removal of llist entry 299 | * @pos: the type * to use as a loop counter. 300 | * @n: another type * to use as temporary storage 301 | * @head: the head for your llist. 302 | * @member: the name of the llist_struct within the struct. 303 | */ 304 | #define llist_for_each_entry_safe(pos, n, head, member) \ 305 | for (pos = llist_entry((head)->next, typeof(*pos), member), \ 306 | n = llist_entry(pos->member.next, typeof(*pos), member); \ 307 | &pos->member != (head); \ 308 | pos = n, n = llist_entry(n->member.next, typeof(*n), member)) 309 | 310 | /** 311 | * llist_for_each_rcu - iterate over an rcu-protected llist 312 | * @pos: the &struct llist_head to use as a loop counter. 313 | * @head: the head for your llist. 314 | */ 315 | #define llist_for_each_rcu(pos, head) \ 316 | for (pos = (head)->next, prefetch(pos->next); pos != (head); \ 317 | pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next)) 318 | 319 | #define __llist_for_each_rcu(pos, head) \ 320 | for (pos = (head)->next; pos != (head); \ 321 | pos = pos->next, ({ smp_read_barrier_depends(); 0;})) 322 | 323 | /** 324 | * llist_for_each_safe_rcu - iterate over an rcu-protected llist safe 325 | * against removal of llist entry 326 | * @pos: the &struct llist_head to use as a loop counter. 327 | * @n: another &struct llist_head to use as temporary storage 328 | * @head: the head for your llist. 329 | */ 330 | #define llist_for_each_safe_rcu(pos, n, head) \ 331 | for (pos = (head)->next, n = pos->next; pos != (head); \ 332 | pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next) 333 | 334 | /** 335 | * llist_for_each_entry_rcu - iterate over rcu llist of given type 336 | * @pos: the type * to use as a loop counter. 337 | * @head: the head for your llist. 338 | * @member: the name of the llist_struct within the struct. 339 | */ 340 | #define llist_for_each_entry_rcu(pos, head, member) \ 341 | for (pos = llist_entry((head)->next, typeof(*pos), member), \ 342 | prefetch(pos->member.next); \ 343 | &pos->member != (head); \ 344 | pos = llist_entry(pos->member.next, typeof(*pos), member), \ 345 | ({ smp_read_barrier_depends(); 0;}), \ 346 | prefetch(pos->member.next)) 347 | 348 | 349 | /** 350 | * llist_for_each_continue_rcu - iterate over an rcu-protected llist 351 | * continuing after existing point. 352 | * @pos: the &struct llist_head to use as a loop counter. 353 | * @head: the head for your llist. 354 | */ 355 | #define llist_for_each_continue_rcu(pos, head) \ 356 | for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \ 357 | (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next)) 358 | 359 | 360 | #endif 361 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "utils.h" 8 | 9 | /*! \addtogroup utils 10 | * @{ 11 | */ 12 | 13 | /*! \file utils.c */ 14 | 15 | static char namebuf[255]; 16 | 17 | /*! \brief get human-readable string for given value 18 | * \param[in] vs Array of value_string tuples 19 | * \param[in] val Value to be converted 20 | * \returns pointer to human-readable string 21 | */ 22 | const char *get_value_string(const struct value_string *vs, uint32_t val) 23 | { 24 | int i; 25 | 26 | for (i = 0;; i++) { 27 | if (vs[i].value == 0 && vs[i].str == NULL) 28 | break; 29 | if (vs[i].value == val) 30 | return vs[i].str; 31 | } 32 | 33 | snprintf(namebuf, sizeof(namebuf), "unknown 0x%x", val); 34 | return namebuf; 35 | } 36 | 37 | /*! \brief get numeric value for given human-readable string 38 | * \param[in] vs Array of value_string tuples 39 | * \param[in] str human-readable string 40 | * \returns numeric value (>0) or negative numer in case of error 41 | */ 42 | int get_string_value(const struct value_string *vs, const char *str) 43 | { 44 | int i; 45 | 46 | for (i = 0;; i++) { 47 | if (vs[i].value == 0 && vs[i].str == NULL) 48 | break; 49 | if (!strcasecmp(vs[i].str, str)) 50 | return vs[i].value; 51 | } 52 | return -EINVAL; 53 | } 54 | 55 | /*! \brief Convert BCD-encoded digit into printable character 56 | * \param[in] bcd A single BCD-encoded digit 57 | * \returns single printable character 58 | */ 59 | char osmo_bcd2char(uint8_t bcd) 60 | { 61 | if (bcd < 0xa) 62 | return '0' + bcd; 63 | else 64 | return 'A' + (bcd - 0xa); 65 | } 66 | 67 | /* only works for numbers in ascii */ 68 | uint8_t osmo_char2bcd(char c) 69 | { 70 | return c - 0x30; 71 | } 72 | 73 | int osmo_hexparse(const char *str, uint8_t *b, int max_len) 74 | 75 | { 76 | int i, l, v; 77 | 78 | l = strlen(str); 79 | if ((l&1) || ((l>>1) > max_len)) 80 | return -1; 81 | 82 | memset(b, 0x00, max_len); 83 | 84 | for (i=0; i= '0' && c <= '9') 87 | v = c - '0'; 88 | else if (c >= 'a' && c <= 'f') 89 | v = 10 + (c - 'a'); 90 | else if (c >= 'A' && c <= 'F') 91 | v = 10 + (c - 'A'); 92 | else 93 | return -1; 94 | b[i>>1] |= v << (i&1 ? 0 : 4); 95 | } 96 | 97 | return i>>1; 98 | } 99 | 100 | static char hexd_buff[4096]; 101 | 102 | static char *_osmo_hexdump(const unsigned char *buf, int len, const char *delim) 103 | { 104 | int i; 105 | char *cur = hexd_buff; 106 | 107 | hexd_buff[0] = 0; 108 | for (i = 0; i < len; i++) { 109 | int len_remain = sizeof(hexd_buff) - (cur - hexd_buff); 110 | if (len_remain <= 0) 111 | break; 112 | int rc = snprintf(cur, len_remain, "%02x%s", buf[i], delim); 113 | if (rc <= 0) 114 | break; 115 | cur += rc; 116 | } 117 | hexd_buff[sizeof(hexd_buff)-1] = 0; 118 | return hexd_buff; 119 | } 120 | 121 | /*! \brief Convert a sequence of unpacked bits to ASCII string 122 | * \param[in] bits A sequence of unpacked bits 123 | * \param[in] len Length of bits 124 | */ 125 | char *osmo_ubit_dump(const uint8_t *bits, unsigned int len) 126 | { 127 | if (len > sizeof(hexd_buff)-1) 128 | len = sizeof(hexd_buff)-1; 129 | memset(hexd_buff, 0, sizeof(hexd_buff)); 130 | 131 | for (unsigned i = 0; i < len; i++) { 132 | char outch; 133 | switch (bits[i]) { 134 | case 0: 135 | outch = '0'; 136 | break; 137 | case 0xff: 138 | outch = '?'; 139 | break; 140 | case 1: 141 | outch = '1'; 142 | break; 143 | default: 144 | outch = 'E'; 145 | break; 146 | } 147 | hexd_buff[i] = outch; 148 | } 149 | hexd_buff[sizeof(hexd_buff)-1] = 0; 150 | return hexd_buff; 151 | } 152 | 153 | /*! \brief Convert binary sequence to hexadecimal ASCII string 154 | * \param[in] buf pointer to sequence of bytes 155 | * \param[in] len length of buf in number of bytes 156 | * \returns pointer to zero-terminated string 157 | * 158 | * This function will print a sequence of bytes as hexadecimal numbers, 159 | * adding one space character between each byte (e.g. "1a ef d9") 160 | */ 161 | char *osmo_hexdump(const unsigned char *buf, int len) 162 | { 163 | return _osmo_hexdump(buf, len, " "); 164 | } 165 | 166 | /*! \brief Convert binary sequence to hexadecimal ASCII string 167 | * \param[in] buf pointer to sequence of bytes 168 | * \param[in] len length of buf in number of bytes 169 | * \returns pointer to zero-terminated string 170 | * 171 | * This function will print a sequence of bytes as hexadecimal numbers, 172 | * without any space character between each byte (e.g. "1aefd9") 173 | */ 174 | char *osmo_hexdump_nospc(const unsigned char *buf, int len) 175 | { 176 | return _osmo_hexdump(buf, len, ""); 177 | } 178 | 179 | /* Compat with previous typo to preserve abi */ 180 | // char *osmo_osmo_hexdump_nospc(const unsigned char *buf, int len) 181 | // __attribute__((weak, alias("osmo_hexdump_nospc"))); 182 | 183 | // #include "../config.h" 184 | #ifdef HAVE_CTYPE_H 185 | #include 186 | /*! \brief Convert an entire string to lower case 187 | * \param[out] out output string, caller-allocated 188 | * \param[in] in input string 189 | */ 190 | void osmo_str2lower(char *out, const char *in) 191 | { 192 | unsigned int i; 193 | 194 | for (i = 0; i < strlen(in); i++) 195 | out[i] = tolower(in[i]); 196 | out[strlen(in)] = '\0'; 197 | } 198 | 199 | /*! \brief Convert an entire string to upper case 200 | * \param[out] out output string, caller-allocated 201 | * \param[in] in input string 202 | */ 203 | void osmo_str2upper(char *out, const char *in) 204 | { 205 | unsigned int i; 206 | 207 | for (i = 0; i < strlen(in); i++) 208 | out[i] = toupper(in[i]); 209 | out[strlen(in)] = '\0'; 210 | } 211 | #endif /* HAVE_CTYPE_H */ 212 | 213 | /*! @} */ 214 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | #ifndef OSMOCORE_UTIL_H 2 | #define OSMOCORE_UTIL_H 3 | 4 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 5 | 6 | #include 7 | 8 | struct value_string { 9 | unsigned int value; 10 | const char *str; 11 | }; 12 | 13 | const char *get_value_string(const struct value_string *vs, uint32_t val); 14 | int get_string_value(const struct value_string *vs, const char *str); 15 | 16 | char *osmo_ubit_dump(const uint8_t *bits, unsigned int len); 17 | char *osmo_hexdump_nospc(const unsigned char *buf, int len); 18 | 19 | int osmo_hexparse(const char *str, uint8_t *b, int max_len); 20 | 21 | 22 | #endif 23 | --------------------------------------------------------------------------------