{"id":21175573,"url":"https://github.com/m3y54m/aes-in-c","last_synced_at":"2025-07-09T21:32:07.973Z","repository":{"id":156124846,"uuid":"381751476","full_name":"m3y54m/aes-in-c","owner":"m3y54m","description":"Basic implementation of AES in C + Tutorial","archived":false,"fork":false,"pushed_at":"2024-06-08T09:01:20.000Z","size":172,"stargazers_count":50,"open_issues_count":1,"forks_count":13,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-05T07:22:58.251Z","etag":null,"topics":["aes","cryptography","rijndael-algorithm"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/m3y54m.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-30T15:36:46.000Z","updated_at":"2025-03-21T08:46:57.000Z","dependencies_parsed_at":"2023-12-13T13:01:33.916Z","dependency_job_id":null,"html_url":"https://github.com/m3y54m/aes-in-c","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/m3y54m/aes-in-c","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m3y54m%2Faes-in-c","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m3y54m%2Faes-in-c/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m3y54m%2Faes-in-c/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m3y54m%2Faes-in-c/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/m3y54m","download_url":"https://codeload.github.com/m3y54m/aes-in-c/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/m3y54m%2Faes-in-c/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264503949,"owners_count":23618762,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aes","cryptography","rijndael-algorithm"],"created_at":"2024-11-20T16:59:57.066Z","updated_at":"2025-07-09T21:32:06.714Z","avatar_url":"https://github.com/m3y54m.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AES Implementation in C\r\n\r\nThis is a very simple (and **NOT a highly optimized and secure**) implementation of AES only written to teach you the **BASICS** of this algorithm. I used a tutorial previously available on [progressive-coding.com](https://web.archive.org/web/20071225102048/http://www.progressive-coding.com/tutorial.php?id=0) to write the C code in this reposistory. The original link to that website is broken and the tutorial is no longer available on the web. You can still find an older version of the tutorial on [cboard.cprogramming.com](https://cboard.cprogramming.com/c-programming/87805-%5Btutorial%5D-implementing-advanced-encryption-standard.html).\r\n\r\nI revised the article, added some comprehensive images, and rewrote it in Markdown and put it here in the `README.md` of my code. \r\n\r\n\u003e [!CAUTION]\r\n\u003e Please note that the code and materials provided in this repository are intended for EDUCATIONAL purposes only and is NOT SAFE to be used in production.\r\n\r\n## Build and run the code\r\n\r\nBuild:\r\n\r\n```\r\nmake\r\n```\r\n\r\nRun:\r\n\r\n```\r\n./build/aes\r\n```\r\n\r\n## Introduction to cryptography:\r\n\r\n1.  [Introduction to cryptography](#introduction-to-cryptography)\r\n2.  [Introduction to the Advanced Encryption Standard](#introduction-to-the-advanced-encryption-standard)\r\n3.  [Description of the AES algorithm](#description-of-the-advanced-encryption-standard-algorithm)\r\n4.  [AES operations: SubBytes, ShiftRow, MixColumn and AddRoundKey](#aes-operations-subbytes-shiftrow-mixcolumn-and-addroundkey)\r\n5.  [The Rijndael Key Schedule](#the-rijndael-key-schedule)\r\n6.  [The Key Expansion](#the-key-expansion)\r\n7.  [Implementation: The Key Schedule](#implementation-the-key-schedule)\r\n8.  [Implementation: AES Encryption](#implementation-aes-encryption)\r\n9.  [AES Decryption](#aes-decryption)\r\n\r\n\r\nSerge Vaudenay, in his book \"A classical introduction to\r\ncryptography\", writes:\r\n\r\n\u003e *Cryptography is the science of information and communication\r\n\u003e security.*\r\n\r\nCryptography is the science of secret codes, enabling the\r\nconfidentiality of communication through an insecure channel. It\r\nprotects against unauthorized parties by preventing unauthorized\r\nalteration of use. Generally speaking, it uses an cryptographic system\r\nto transform a plaintext into a ciphertext, using most of the time a\r\nkey.\r\n\r\nOne has to notice that there exist certain cipher that don't need a key\r\nat all. A famous example is [ROT13](http://en.wikipedia.org/wiki/Rot13)\r\n(abbreviation from Rotation 13), a simple Caesar-cipher that obscures\r\ntext by replacing each letter with the letter thirteen places down in\r\nthe alphabet. Since our alphabet has 26 characters, it is enough to\r\nencrypt the ciphertext again to retrieve the original message.\r\n\r\nLet me just mention briefly that there are secure public-key ciphers,\r\nlike the famous and very secure\r\n[Rivest-Shamir-Adleman](http://en.wikipedia.org/wiki/RSA) (commonly\r\ncalled RSA) that uses a public key to encrypt a message and a secret key\r\nto decrypt it.\r\n\r\nCryptography is a very important domain in computer science with many\r\napplications. The most famous example of cryptography is certainly the\r\n[Enigma machine](http://en.wikipedia.org/wiki/Enigma_machine), the\r\nlegendary cipher machine used by the German Third Reich to encrypt their\r\nmessages, who's security breach ultimately led to the defeat of their\r\nsubmarine force.\r\n\r\nBefore continuing, please read carefully the [legal issues involving\r\ncryptography](http://en.wikipedia.org/wiki/Cryptography#Legal_issues_involving_cryptography)\r\nas in several countries even the domestic use of cryptography is\r\nprohibited:\r\n\r\n\u003e Cryptography has long been of interest to intelligence gathering\r\n\u003e agencies and law enforcement agencies. Because of its facilitation of\r\n\u003e privacy, and the diminution of privacy attendant on its prohibition,\r\n\u003e cryptography is also of considerable interest to civil rights\r\n\u003e supporters. Accordingly, there has been a history of controversial\r\n\u003e legal issues surrounding cryptography, especially since the advent of\r\n\u003e inexpensive computers has made possible widespread access to high\r\n\u003e quality cryptography.\r\n\u003e\r\n\u003e In some countries, even the domestic use of cryptography is, or has\r\n\u003e been, restricted. Until 1999, France significantly restricted the use\r\n\u003e of cryptography domestically. In China, a license is still required to\r\n\u003e use cryptography. Many countries have tight restrictions on the use of\r\n\u003e cryptography. Among the more restrictive are laws in Belarus,\r\n\u003e Kazakhstan, Mongolia, Pakistan, Russia, Singapore, Tunisia, Venezuela,\r\n\u003e and Vietnam.\\[31\\]\r\n\u003e\r\n\u003e In the United States, cryptography is legal for domestic use, but\r\n\u003e there has been much conflict over legal issues related to\r\n\u003e cryptography. One particularly important issue has been the export of\r\n\u003e cryptography and cryptographic software and hardware. Because of the\r\n\u003e importance of cryptanalysis in World War II and an expectation that\r\n\u003e cryptography would continue to be important for national security,\r\n\u003e many western governments have, at some point, strictly regulated\r\n\u003e export of cryptography. After World War II, it was illegal in the US\r\n\u003e to sell or distribute encryption technology overseas; in fact,\r\n\u003e encryption was classified as a munition, like tanks and nuclear\r\n\u003e weapons.\\[32\\] Until the advent of the personal computer and the\r\n\u003e Internet, this was not especially problematic. Good cryptography is\r\n\u003e indistinguishable from bad cryptography for nearly all users, and in\r\n\u003e any case, most of the cryptographic techniques generally available\r\n\u003e were slow and error prone whether good or bad. However, as the\r\n\u003e Internet grew and computers became more widely available, high quality\r\n\u003e encryption techniques became well-known around the globe. As a result,\r\n\u003e export controls came to be seen to be an impediment to commerce and to\r\n\u003e research.\r\n\r\n## Introduction to the Advanced Encryption Standard:\r\n\r\nThe Advanced Encryption Standard, in the following referenced as AES, is\r\nthe winner of the contest, held in 1997 by the US Government, after the\r\n[Data Encryption\r\nStandard](http://en.wikipedia.org/wiki/Data_Encryption_Standard) was\r\nfound too weak because of its small key size and the technological\r\nadvancements in processor power. Fifteen candidates were accepted in\r\n1998 and based on public comments the pool was reduced to five finalists\r\nin 1999. In October 2000, one of these five algorithms was selected as\r\nthe forthcoming standard: a slightly modified version of the Rijndael.\r\n\r\nThe Rijndael, whose name is based on the names of its two Belgian\r\ninventors, [Joan Daemen](http://en.wikipedia.org/wiki/Joan_Daemen) and\r\n[Vincent Rijmen](http://en.wikipedia.org/wiki/Vincent_Rijmen), is a\r\n[Block cipher](http://en.wikipedia.org/wiki/Block_cipher), which means\r\nthat it works on fixed-length group of bits, which are called *blocks*.\r\nIt takes an input block of a certain size, usually 128, and produces a\r\ncorresponding output block of the same size. The transformation requires\r\na second input, which is the secret key. It is important to know that\r\nthe secret key can be of any size (depending on the cipher used) and\r\nthat AES uses three different key sizes: 128, 192 and 256 bits.\r\n\r\nTo encrypt messages longer than the block size, a [mode of\r\noperation](http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation)\r\nis chosen, which I will explain at the very end of this tutorial, after\r\nthe implementation of AES.\r\n\r\nWhile AES supports only block sizes of 128 bits and key sizes of 128,\r\n192 and 256 bits, the original Rijndael supports key and block sizes in\r\nany multiple of 32, with a minimum of 128 and a maximum of 256 bits.\r\n\r\n### Further readings:\r\n\r\nUnlike DES, which is based on an [Feistel\r\nnetwork](http://en.wikipedia.org/wiki/Feistel_network), AES is a\r\n[substitution-permutation\r\nnetwork](http://en.wikipedia.org/wiki/Substitution-permutation_network),\r\nwhich is a series of mathematical operations that use substitutions\r\n(also called S-Box) and permutations (P-Boxes) and their careful\r\ndefinition implies that each output bit depends on every input bit.\r\n\r\n## Description of the Advanced Encryption Standard algorithm\r\n\r\nAES is an iterated block cipher with a fixed block size of 128 and a\r\nvariable key length. The different transformations operate on the\r\nintermediate results, called *state*. The state is a rectangular array\r\nof bytes and since the block size is 128 bits, which is 16 bytes, the\r\nrectangular array is of dimensions 4x4. (In the Rijndael version with\r\nvariable block size, the row size is fixed to four and the number of\r\ncolumns vary. The number of columns is the block size divided by 32 and\r\ndenoted Nb). The cipher key is similarly pictured as a rectangular array\r\nwith four rows. The number of columns of the cipher key, denoted Nk, is\r\nequal to the key length divided by 32.\r\n\r\n![image](https://user-images.githubusercontent.com/1549028/234524844-c4aabe3b-eab8-4897-82f6-28abf2ec1b5d.png)\r\n\r\n``` \r\nA state:\r\n-----------------------------\r\n| a0,0 | a0,1 | a0,2 | a0,3 |\r\n| a1,0 | a1,1 | a1,2 | a1,3 |\r\n| a2,0 | a2,1 | a2,2 | a2,3 |\r\n| a3,0 | a3,1 | a3,2 | a3,3 |\r\n-----------------------------\r\n\r\nA key:\r\n-----------------------------\r\n| k0,0 | k0,1 | k0,2 | k0,3 |\r\n| k1,0 | k1,1 | k1,2 | k1,3 |\r\n| k2,0 | k2,1 | k2,2 | k2,3 |\r\n| k3,0 | k3,1 | k3,2 | k3,3 |\r\n-----------------------------\r\n```\r\n\r\nIt is very *important* to know that the cipher input bytes are mapped\r\nonto the the state bytes in the order a0,0, a1,0, a2,0, a3,0, a0,1,\r\na1,1, a2,1, a3,1 \\... and the bytes of the cipher key are mapped onto\r\nthe array in the order k0,0, k1,0, k2,0, k3,0, k0,1, k1,1, k2,1, k3,1\r\n\\... At the end of the cipher operation, the cipher output is extracted\r\nfrom the state by taking the state bytes in the same order. AES uses a\r\nvariable number of rounds, which are fixed: A key of size 128 has 10\r\nrounds. A key of size 192 has 12 rounds. A key of size 256 has 14\r\nrounds. During each round, the following operations are applied on the\r\nstate:\r\n\r\n1.  SubBytes: every byte in the state is replaced by another one, using\r\n    the Rijndael S-Box\r\n2.  ShiftRow: every row in the 4x4 array is shifted a certain amount to\r\n    the left\r\n3.  MixColumn: a linear transformation on the columns of the state\r\n4.  AddRoundKey: each byte of the state is combined with a round key,\r\n    which is a different key for each round and derived from the\r\n    Rijndael key schedule\r\n\r\nIn the final round, the MixColumn operation is omitted. The algorithm\r\nlooks like the following (pseudo-C):\r\n\r\n```c \r\nAES(state, CipherKey)\r\n{\r\n    KeyExpansion(CipherKey, ExpandedKey);\r\n    AddRoundKey(state, ExpandedKey);\r\n    for (i = 1; i \u003c Nr; i++)\r\n    {\r\n        Round(state, ExpandedKey + Nb*i);\r\n    }\r\n    FinalRound(state, ExpandedKey + Nb * Nr);\r\n}\r\n```\r\n\r\n![image](https://user-images.githubusercontent.com/1549028/234524395-752bb3be-813c-40ff-8dd0-f0a02029d229.png)\r\n\r\n### Observations:\r\n\r\n-   The cipher key is expanded into a larger key, which is later used\r\n    for the actual operations\r\n-   The roundKey is added to the state before starting the with loop\r\n-   The FinalRound() is the same as Round(), apart from missing the\r\n    MixColumns() operation.\r\n-   During each round, another part of the ExpandedKey is used for the\r\n    operations\r\n-   The ExpandedKey shall ALWAYS be derived from the Cipher Key and\r\n    never be specified directly.\r\n\r\n## AES operations: SubBytes, ShiftRow, MixColumn and AddRoundKey\r\n\r\n### The AddRoundKey operation:\r\n\r\nIn this operation, a Round Key is applied to the state by a simple\r\nbitwise XOR. The Round Key is derived from the Cipher Key by the means\r\nof the key schedule. The Round Key length is equal to the block key\r\nlength (=16 bytes).\r\n\r\n``` \r\n-----------------------------       -----------------------------   -----------------------------\r\n| a0,0 | a0,1 | a0,2 | a0,3 |       | k0,0 | k0,1 | k0,2 | k0,3 |   | b0,0 | b0,1 | b0,2 | b0,3 |\r\n| a1,0 | a1,1 | a1,2 | a1,3 |  XOR  | k2,0 | k2,1 | k2,2 | k2,3 | = | b2,0 | b2,1 | b2,2 | b2,3 |\r\n| a2,0 | a2,1 | a2,2 | a2,3 |       | k1,0 | k1,1 | k1,2 | k1,3 |   | b1,0 | b1,1 | b1,2 | b1,3 |\r\n| a3,0 | a3,1 | a3,2 | a3,3 |       | k3,0 | k3,1 | k3,2 | k3,3 |   | b3,0 | b3,1 | b3,2 | b3,3 |\r\n-----------------------------       -----------------------------   -----------------------------\r\n\r\nwhere: b(i,j) = a(i,j) XOR k(i,j)\r\n```\r\n\r\nA graphical representation of this operation can be seen below:\r\n\r\n![image](https://user-images.githubusercontent.com/1549028/234528702-5610357c-50d2-4090-b8e8-0dab12024470.png)\r\n\r\n### The ShiftRow operation:\r\n\r\nIn this operation, each row of the state is cyclically shifted to the\r\nleft, depending on the row index.\r\n\r\n-   The 1st row is shifted 0 positions to the left.\r\n-   The 2nd row is shifted 1 positions to the left.\r\n-   The 3rd row is shifted 2 positions to the left.\r\n-   The 4th row is shifted 3 positions to the left.\r\n\r\n``` \r\n-----------------------------    -----------------------------\r\n| a0,0 | a0,1 | a0,2 | a0,3 |    | a0,0 | a0,1 | a0,2 | a0,3 |\r\n| a1,0 | a1,1 | a1,2 | a1,3 | -\u003e | a1,1 | a1,2 | a1,3 | a1,0 |\r\n| a2,0 | a2,1 | a2,2 | a2,3 |    | a2,2 | a2,3 | a2,0 | a2,1 |\r\n| a3,0 | a3,1 | a3,2 | a3,3 |    | a3,3 | a3,0 | a3,1 | a3,2 |\r\n-----------------------------    -----------------------------\r\n```\r\nA graphical representation of this operation can be found below:\r\n\r\n![image](https://user-images.githubusercontent.com/1549028/234527634-c85f1b7b-6978-4f2e-9006-b7dec501b0e6.png)\r\n\r\nPlease note that the inverse of ShiftRow is the same cyclically shift\r\nbut this time to the right. It will be needed later for decoding.\r\n\r\n### The SubBytes operation:\r\n\r\nThe SubBytes operation is a non-linear byte substitution, operating on\r\neach byte of the state independently. The [substitution table\r\n(S-Box)](http://en.wikipedia.org/wiki/Rijndael_S-box) is invertible and\r\nis constructed by the composition of two transformations:\r\n\r\n1.  Take the multiplicative inverse in [Rijndael's finite\r\n    field](http://en.wikipedia.org/wiki/Finite_field_arithmetic)\r\n2.  Apply an affine transformation which is documented in the Rijndael\r\n    documentation.\r\n\r\nSince the S-Box is independent of any input, pre-calculated forms are\r\nused, if enough memory (256 bytes for one S-Box) is available. Each byte\r\nof the state is then substituted by the value in the S-Box whose index\r\ncorresponds to the value in the state:\r\n\r\n```c \r\na(i,j) = SBox[a(i,j)]\r\n```\r\n\r\n![image](https://user-images.githubusercontent.com/1549028/234528874-4cafa80c-01c0-4d59-a0a4-feb76e5243b2.png)\r\n\r\nPlease note that the inverse of SubBytes is the same operation, using\r\nthe inversed S-Box, which is also precalculated.\r\n\r\n### The MixColumn operation:\r\n\r\nI will keep this section very short since it involves a lot of very\r\nadvance mathematical calculations in the [Rijndael's finite\r\nfield](http://en.wikipedia.org/wiki/Finite_field_arithmetic). All you\r\nhave to know is that it corresponds to the matrix multiplication with:\r\n\r\n``` \r\n2 3 1 1\r\n1 2 3 1\r\n1 1 2 3\r\n3 1 1 2\r\n```\r\n\r\nand that the addition and multiplication operations are a little\r\ndifferent from the normal ones.\r\n\r\nYou can skip this part if you are not interested in the math involved:\r\n\r\n\u003e Addition and Substraction:\r\n\u003e\r\n\u003e Addition and subtraction are performed by the exclusive or operation.\r\n\u003e The two operations are the same; there is no difference between\r\n\u003e addition and subtraction.\r\n\u003e\r\n\u003e Multiplication in Rijndael's galois field is a little more\r\n\u003e complicated. The procedure is as follows:\r\n\u003e\r\n\u003e -   Take two eight-bit numbers, a and b, and an eight-bit product p\r\n\u003e\r\n\u003e -   Set the product to zero.\r\n\u003e\r\n\u003e -   Make a copy of a and b, which we will simply call a and b in the\r\n\u003e     rest of this algorithm\r\n\u003e\r\n\u003e\r\n\u003e     Run the following loop eight times:\r\n\u003e\r\n\u003e         1.  If the low bit of b is set, exclusive or the product p by\r\n\u003e             the value of a\r\n\u003e         2.  Keep track of whether the high (eighth from left) bit of a\r\n\u003e             is set to one\r\n\u003e         3.  Rotate a one bit to the left, discarding the high bit, and\r\n\u003e             making the low bit have a value of zero\r\n\u003e         4.  If a's hi bit had a value of one prior to this rotation,\r\n\u003e             exclusive or a with the hexadecimal number 0x1b\r\n\u003e         5.  Rotate b one bit to the right, discarding the low bit, and\r\n\u003e             making the high (eighth from left) bit have a value of\r\n\u003e             zero.\r\n\u003e\r\n\u003e -   The product p now has the product of a and b\r\n\u003e\r\n\u003e Thanks to [Sam Trenholme](http://www.samiam.org/) for writing this\r\n\u003e explanation.\r\n\r\n![image](https://user-images.githubusercontent.com/1549028/234528985-b6a569ea-9ba0-4897-b803-16919738b811.png)\r\n\r\n## The Rijndael Key Schedule:\r\n\r\nThe Key Schedule is responsible for expanding a short key into a larger\r\nkey, whose parts are used during the different iterations. Each key size\r\nis expanded to a different size:\r\n\r\n-   An 128 bit key is expanded to an 176 byte key.\r\n-   An 192 bit key is expanded to an 208 byte key.\r\n-   An 256 bit key is expanded to an 240 byte key.\r\n\r\nThere is a relation between the cipher key size, the number of rounds\r\nand the ExpandedKey size. For an 128-bit key, there is one initial\r\nAddRoundKey operation plus there are 10 rounds and each round needs a\r\nnew 16 byte key, therefor we require 10+1 RoundKeys of 16 byte, which\r\nequals 176 byte. The same logic can be applied to the two other cipher\r\nkey sizes. The general formula is that:\r\n\r\nExpandedKeySize = (nbrRounds+1) \\* BlockSize\r\n\r\nThe Key Schedule is made up of iterations of the Key schedule core,\r\nwhich works on 4-byte *words*. The core uses a certain number of\r\noperations, which are explained here:\r\n\r\n### Rotate:\r\n\r\nThe 4-byte word is cyclically shifted 1 byte to the left:\r\n\r\n``` \r\n---------------------    ---------------------\r\n| 1d | 2c | 3a | 4f | -\u003e | 2c | 3a | 4f | 1d |\r\n---------------------    ---------------------\r\n```\r\n\r\n### Rcon:\r\n\r\nThis section is again extremely mathematical and I recommend everyone\r\nwho is interested to read [this\r\ndescription](http://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon).\r\nJust note that the Rcon values can be pre-calculated, which results in a\r\nsimple substitution (a table lookup) in a fixed Rcon table (again, Rcon\r\ncan also be calculated on-the-fly if memory is a design constraint.)\r\n\r\n### S-Box:\r\n\r\nThe Key Schedule uses the same S-Box substitution as the main algorithm\r\nbody.\r\n\r\n### The Key Schedule Core:\r\n\r\nNow that we know what the operations are, let me show you the key\r\nschedule core (in pseudo-C):\r\n\r\n```c \r\nkeyScheduleCore(word)\r\n{\r\n    Rotate(word);\r\n    SBoxSubstitution(word);\r\n    word[0] = word[0] XOR RCON[i];\r\n}\r\n```\r\n\r\nIn the above code, word has a size of 4 bytes and i is the iteration\r\ncounter from the Key Schedule\r\n\r\n## The Key Expansion:\r\n\r\nFirst, let me show you the keyExpansion function as you can find it in\r\nthe Rijndael documentation (there are 2 version, one for key size 128,\r\n192 and one for key size 256):\r\n\r\n```c \r\nKeyExpansion(byte Key[4*Nk] word W[Nb*(Nr+1)])\r\n{\r\n    for(i = 0; i \u003c Nk; i++)\r\n        W[i] = (Key[4*i],Key[4*i+1],Key[4*i+2],Key[4*i+3]);\r\n    for(i = Nk; i \u003c Nb * (Nr + 1); i++)\r\n    {\r\n        temp = W[i - 1];\r\n        if (i % Nk == 0)\r\n            temp = SubByte(RotByte(temp)) ^ Rcon[i / Nk];\r\n        W[i] = W[i - Nk] ^ temp;\r\n    }\r\n}\r\n```\r\n\r\n-   Nk is the number of columns in the cipher key (128-bit -\\\u003e 4,\r\n    192-bit -\\\u003e 5, 256-bit -\\\u003e 6)\r\n-   W is of type \"word\", which is 4-bytes\r\n\r\nLet me try to explain this in an easier understandable way:\r\n\r\n-   The first n bytes of the expanded key are simply the cipher key (n =\r\n    the size of the encryption key)\r\n-   The rcon value i is set to 1\r\n-   Until we have enough bytes of expanded key, we do the following to\r\n    generate n more bytes of expanded key (please note once again that\r\n    \"n\" is used here, this varies depending on the key size)\r\n    1.  we do the following to generate four bytes\r\n        -   we use a temporary 4-byte word called t\r\n        -   we assign the previous 4 bytes to t\r\n        -   we perform the key schedule core on t, with i as rcon value\r\n        -   we increment i\r\n        -   we XOR t with the 4-byte word n bytes before in the\r\n            expandedKey (where n is once either either 16,24 or 32\r\n            bytes)\r\n    2.  we do the following x times to generate the next x\\*4 bytes of\r\n        the expandedKey (x = 3 for n=16,32 and x = 5 for n=24)\r\n        -   we assign the previous 4-byte word to t\r\n        -   we XOR t with the 4-byte word n bytes before in the\r\n            expandedKey (where n is once either either 16,24 or 32\r\n            bytes)\r\n    3.  if n = 32 (and ONLY then), we do the following to generate 4\r\n        more bytes\r\n        -   we assign the previous 4-byte word to t\r\n        -   We run each of the four bytes in t through Rijndael's S-box\r\n        -   we XOR t with the 4-byte word 32 bytes before in the\r\n            expandedKey\r\n    4.  if n = 32 (and ONLY then), we do the following three times to\r\n        generate twelve more bytes\r\n        -   we assign the previous 4-byte word to t\r\n        -   we XOR t with the 4-byte word 32 bytes before in the\r\n            expandedKey\r\n-   We now have our expandedKey\r\n\r\n![image](https://user-images.githubusercontent.com/1549028/234530304-2cec67ef-a750-4008-b6e3-ff29a95dcdd4.png)\r\n\r\nDon't worry if you still have problems understanding the Key Schedule,\r\nyou'll see that the implementation isn't very hard. What you should\r\nnote is that:\r\n\r\n-   the part in red is only for cipher key size = 32\r\n-   for n=16, we generate: 4 + 3\\*4 bytes = 16 bytes per iteration\r\n-   for n=24, we generate: 4 + 5\\*4 bytes = 24 bytes per iteration\r\n-   for n=32, we generate: 4 + 3\\*4 + 4 + 3\\*4 = 32 bytes per iteration\r\n\r\nThe implementation of the key schedule is pretty straight forward, but\r\nsince there is a lot of code repetition, it is possible to optimize the\r\nloop slightly and use the modulo operator to check when the additional\r\noperations have to be made.\r\n\r\n## Implementation: The Key Schedule\r\n\r\nWe will start the implementation of AES with the Cipher Key expansion.\r\nAs you can read in the theoretical part above, we intend to enlarge our\r\ninput cipher key, whose size varies between 128 and 256 bits into a\r\nlarger key, from which different RoundKeys can be derived.\r\n\r\nI prefer to implement the helper functions (such as rotate, Rcon or\r\nS-Box first), test them and then move on to the larger loops. If you are\r\nnot a fan of bottom-up approaches, feel free to start a little further\r\nin this tutorial and move your way up, but I felt that my approach was\r\nthe more logical one here.\r\n\r\n### Implementation: General comments\r\n\r\nEven though some might think that integers were the best choice to work\r\nwith, since their 32 bit size best corresponds one *word*, I strongly\r\ndiscourage you from using integers. You wrongly assume that integers, or\r\nmore specifically the \"int\" type, always has 4 bytes. However, the\r\nrequired ranges for signed and unsigned int are identical to those for\r\nsigned and unsigned short. On compilers for 8 and 16 bit processors\r\n(including Intel x86 processors executing in 16 bit mode, such as under\r\nMS-DOS), an int is usually 16 bits and has exactly the same\r\nrepresentation as a short. On compilers for 32 bit and larger processors\r\n(including Intel x86 processors executing in 32 bit mode, such as Win32\r\nor Linux) an int is usually 32 bits long and has exactly the same\r\nrepresentation as a long. \\| For this very reason, we will be using\r\nunsigned chars, since the size of an char (which is called CHAR_BIT and\r\ndefined in limits.h) is required to be at least 8. Jack Klein wrote:\r\n\r\nAlmost all modern computers today use 8 bit bytes (technically called\r\noctets, but there are still some in production and use with other sizes,\r\nsuch as 9 bits. Also some processors (especially Digital Signal\r\nProcessors) cannot efficiently access memory in smaller pieces than the\r\nprocessor's word size. There is at least one DSP I have worked with\r\nwhere CHAR_BIT is 32. The char types, short, int and long are all 32\r\nbits.\r\n\r\nSince we want to keep our code as portable as possible and since it is\r\nup to the compiler to decide if the default type for char is signed or\r\nnot, we will specify unsigned char throughout the entire code.\r\n\r\n### Implementation: S-Box\r\n\r\nThe S-Box values can either be calculated on-the-fly to save memory or\r\nthe pre-calculated values can be stored in an array. Since I assume that\r\nevery machine my code runs on will have at least 2x 256bytes (there are\r\n2 S-Boxes, one for the encryption and one for the decryption) we will\r\nstore the values in an array. Additionally, instead of accessing the\r\nvalues immediately from our program, I'll wrap a little function around\r\nwhich makes for a more readable code and would allow us to add\r\nadditional code later on. Of course, this is a matter of taste, feel\r\nfree to access the array immediately.\r\n\r\n![image](https://user-images.githubusercontent.com/1549028/234526149-a368a6c6-50d4-403e-82f1-0b1317b0e2ba.png)\r\n\r\nHere's the code for the 2 S-Boxes, it's only a table-lookup that\r\nreturns the value in the array whose index is specified as a parameter\r\nof the function:\r\n\r\n```c \r\nunsigned char sbox[256] =   {\r\n//0     1    2      3     4    5     6     7      8    9     A      B    C     D     E     F\r\n0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, //0\r\n0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, //1\r\n0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, //2\r\n0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, //3\r\n0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, //4\r\n0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, //5\r\n0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, //6\r\n0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, //7\r\n0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, //8\r\n0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, //9\r\n0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, //A\r\n0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, //B\r\n0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, //C\r\n0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, //D\r\n0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, //E\r\n0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; //F\r\n\r\nunsigned char rsbox[256] =\r\n{ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb\r\n, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb\r\n, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e\r\n, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25\r\n, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92\r\n, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84\r\n, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06\r\n, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b\r\n, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73\r\n, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e\r\n, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b\r\n, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4\r\n, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f\r\n, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef\r\n, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61\r\n, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };\r\n\r\nunsigned char getSBoxValue(unsigned char num)\r\n{\r\n    return sbox[num];\r\n}\r\n\r\nunsigned char getSBoxInvert(unsigned char num)\r\n{\r\n    return rsbox[num];\r\n}\r\n```\r\n\r\n### Implementation: Rotate\r\n\r\nFrom the theoretical part, you should know already that Rotate takes a\r\nword (a 4-byte array) and rotates it 8 bit to the left. Since 8 bit\r\ncorrespond to one byte and our array type is character (whose size is\r\none byte), rotating 8 bit to the left corresponds to shifting cyclically\r\nthe array values one to the left.\r\n\r\nHere's the code for the Rotate function:\r\n\r\n```c \r\n/* Rijndael's key schedule rotate operation\r\n * rotate the word eight bits to the left\r\n *\r\n * rotate(1d2c3a4f) = 2c3a4f1d\r\n *\r\n * word is an char array of size 4 (32 bit)\r\n */\r\nvoid rotate(unsigned char *word)\r\n{\r\n    unsigned char c;\r\n    int i;\r\n\r\n    c = word[0];\r\n    for (i = 0; i \u003c 3; i++)\r\n        word[i] = word[i+1];\r\n    word[3] = c;\r\n}\r\n```\r\n\r\n### Implementation: Rcon\r\n\r\nSame as with the S-Box, the Rcon values can be calculated on-the-fly but\r\nonce again I decide to store them in an array since they only require\r\n255 bytes of space. To keep in line with the S-Box implementation, I\r\nwrite a little access function.\r\n\r\nHere's the code for Rcon:\r\n\r\n```c \r\nunsigned char Rcon[255] = {\r\n\r\n0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,\r\n0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,\r\n0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,\r\n0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d,\r\n0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab,\r\n0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,\r\n0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25,\r\n0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01,\r\n0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,\r\n0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa,\r\n0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a,\r\n0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,\r\n0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,\r\n0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,\r\n0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,\r\n0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,\r\n0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f,\r\n0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,\r\n0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33,\r\n0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb};\r\n\r\nunsigned char getRconValue(unsigned char num)\r\n{\r\n    return Rcon[num];\r\n}\r\n```\r\n\r\n### Implementation: Key Schedule Core\r\n\r\nThe implementation of the Key Schedule Core from the pseudo-C is pretty\r\neasy. All the code does is apply the operations one after the other on\r\nthe 4-byte word. The parameters are the 4-byte word and the iteration\r\ncounter, on which Rcon depends.\r\n\r\n```c \r\nvoid core(unsigned char *word, int iteration)\r\n{\r\n    int i;\r\n\r\n    /* rotate the 32-bit word 8 bits to the left */\r\n    rotate(word);\r\n\r\n    /* apply S-Box substitution on all 4 parts of the 32-bit word */\r\n    for (i = 0; i \u003c 4; ++i)\r\n    {\r\n        word[i] = getSBoxValue(word[i]);\r\n    }\r\n\r\n    /* XOR the output of the rcon operation with i to the first part (leftmost) only */\r\n    word[0] = word[0]^getRconValue(iteration);\r\n}\r\n```\r\n\r\n### Implementation: Key Expansion\r\n\r\nThe Key Expansion is where it all comes together. As you can see in the\r\npretty big list in the theory about the Rijndael Key Expansion, we need\r\nto apply several operations a number of times, depending on they key\r\nsize. As the key size can only take a very limited number of values, I\r\ndecided to implement it as an enumeration type. Not only does that limit\r\nthe key size to only three possible values, it also makes the code more\r\nreadable.\r\n\r\n```c\r\nenum keySize{\r\n    SIZE_16 = 16,\r\n    SIZE_24 = 24,\r\n    SIZE_32 = 32\r\n    };\r\n```\r\n\r\nOur key expansion function basically needs only two things:\r\n\r\n-   the input cipher key\r\n-   the output expanded key\r\n\r\nSince in C, it is not possible to know the size of an array passed as\r\npointer to a function, we'll add the cipher key size (of type \"enum\r\nkeySize\") and the expanded key size (of type size_t) to the parameter\r\nlist of our function. The prototype looks like the following:\r\n\r\n```c \r\nvoid expandKey(unsigned char *expandedKey, unsigned char *key, enum keySize, size_t expandedKeySize);\r\n```\r\n\r\nWhile implementing the function, I try to follow the details in the\r\ntheoretical list as close as possible. As I already explained, since\r\nseveral parts of the code are repeated, I'll try to get rid of the code\r\nrepetition and use conditions to see when I need to use a certain\r\noperation.\r\n\r\nInstead of writing:\r\n\r\n```c \r\nwhile (expanded_key_size \u003c required_key_size)\r\n{\r\n    key_schedule_core(word);\r\n    for (i=0; i\u003c4; i++)\r\n        some_operation();\r\n}\r\n```\r\n\r\nI'll use a different structure:\r\n\r\n```c \r\nwhile (expanded_key_size \u003c required_key_size)\r\n{\r\n    if (expanded_key_size%key_size == 0)\r\n        key_schedule_core(word);\r\n    some_operation();\r\n}\r\n```\r\n\r\nThis structure comes down to the same thing, but allows me to be more\r\nflexible when it comes to add the 256-bit cipherkey version that has\r\nthose additional steps.\r\n\r\nLet me show you the keyexpansion function and give explanations later\r\non:\r\n\r\n```c \r\n/* Rijndael's key expansion\r\n * expands an 128,192,256 key into an 176,208,240 bytes key\r\n *\r\n * expandedKey is a pointer to an char array of large enough size\r\n * key is a pointer to a non-expanded key\r\n */\r\n\r\nvoid expandKey(unsigned char *expandedKey,\r\n               unsigned char *key,\r\n               enum keySize size,\r\n               size_t expandedKeySize)\r\n{\r\n    /* current expanded keySize, in bytes */\r\n    int currentSize = 0;\r\n    int rconIteration = 1;\r\n    int i;\r\n    unsigned char t[4] = {0};   // temporary 4-byte variable\r\n\r\n    /* set the 16,24,32 bytes of the expanded key to the input key */\r\n    for (i = 0; i \u003c size; i++)\r\n        expandedKey[i] = key[i];\r\n    currentSize += size;\r\n\r\n    while (currentSize \u003c expandedKeySize)\r\n    {\r\n        /* assign the previous 4 bytes to the temporary value t */\r\n        for (i = 0; i \u003c 4; i++)\r\n        {\r\n            t[i] = expandedKey[(currentSize - 4) + i];\r\n        }\r\n\r\n        /* every 16,24,32 bytes we apply the core schedule to t\r\n         * and increment rconIteration afterwards\r\n         */\r\n        if(currentSize % size == 0)\r\n        {\r\n            core(t, rconIteration++);\r\n        }\r\n\r\n        /* For 256-bit keys, we add an extra sbox to the calculation */\r\n        if(size == SIZE_32 \u0026\u0026 ((currentSize % size) == 16)) {\r\n            for(i = 0; i \u003c 4; i++)\r\n                t[i] = getSBoxValue(t[i]);\r\n        }\r\n\r\n        /* We XOR t with the four-byte block 16,24,32 bytes before the new expanded key.\r\n         * This becomes the next four bytes in the expanded key.\r\n         */\r\n        for(i = 0; i \u003c 4; i++) {\r\n            expandedKey[currentSize] = expandedKey[currentSize - size] ^ t[i];\r\n            currentSize++;\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nAs you can see, I never use inner loops to repeat an operation, the only\r\ninner loops are to iterate over the 4 parts of the temporary array t. I\r\nuse the modulo operator to check if I need to apply the operation:\r\n\r\n-   *if(currentSize % size == 0)*: whenever we have have created n bytes\r\n    of expandedKey (where n is the cipherkey size), we run the key\r\n    expansion core once\r\n-   *if(size == SIZE_32 \u0026\u0026 ((currentSize % size) == 16))*: if we are\r\n    expanding an 32-bit cipherkey and if we have already generated 16\r\n    bytes (as I explained above, in the 32-bit version we run the first\r\n    loop only 3 times, which generates 12 bytes + the 4 bytes from the\r\n    core), we add one additional S-Box substitution\r\n\r\n### Implementation: Using the Key Expansion\r\n\r\nFinally, we can test our newly created key expansion. I won't calculate\r\nthe expandedKey size just yet but rather give it a fixed value (the\r\ncalculation requires the number of rounds which isn't needed at this\r\npoint). Here's the code that would expand a given cipher key:\r\n\r\n```c \r\n/* the expanded keySize */\r\nint expandedKeySize = 176;\r\n\r\n/* the expanded key */\r\nunsigned char expandedKey[expandedKeySize];\r\n\r\n/* the cipher key */\r\nunsigned char key[16] = {0};\r\n\r\n/* the cipher key size */\r\nenum keySize size = SIZE_16;\r\n\r\nint i;\r\n\r\nexpandKey(expandedKey, key, size, expandedKeySize);\r\n\r\nprintf(\"Expanded Key:n\");\r\nfor (i = 0; i \u003c expandedKeySize; i++)\r\n{\r\n        printf(\"%2.2x%c\", expandedKey[i], (i%16) ? 'n' : ' ');\r\n}\r\n```\r\n\r\nOf course, this code uses several constants that will be generated\r\nautomatically once we implement the body of the AES encryption.\r\n\r\nHere are several test results:\r\n\r\nThe Key Expansion of an 128-bit key consisting of null characters (like\r\nthe example above):\r\n\r\n``` \r\n00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\r\n62 63 63 63 62 63 63 63 62 63 63 63 62 63 63 63\r\n9b 98 98 c9 f9 fb fb aa 9b 98 98 c9 f9 fb fb aa\r\n90 97 34 50 69 6c cf fa f2 f4 57 33 0b 0f ac 99\r\nee 06 da 7b 87 6a 15 81 75 9e 42 b2 7e 91 ee 2b\r\n7f 2e 2b 88 f8 44 3e 09 8d da 7c bb f3 4b 92 90\r\nec 61 4b 85 14 25 75 8c 99 ff 09 37 6a b4 9b a7\r\n21 75 17 87 35 50 62 0b ac af 6b 3c c6 1b f0 9b\r\n0e f9 03 33 3b a9 61 38 97 06 0a 04 51 1d fa 9f\r\nb1 d4 d8 e2 8a 7d b9 da 1d 7b b3 de 4c 66 49 41\r\nb4 ef 5b cb 3e 92 e2 11 23 e9 51 cf 6f 8f 18 8e\r\n```\r\n\r\nThe Key Expansion of an 192-bit key consisting of null characters:\r\n\r\n``` \r\n00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\r\n00 00 00 00 00 00 00 00 62 63 63 63 62 63 63 63\r\n62 63 63 63 62 63 63 63 62 63 63 63 62 63 63 63\r\n9b 98 98 c9 f9 fb fb aa 9b 98 98 c9 f9 fb fb aa\r\n9b 98 98 c9 f9 fb fb aa 90 97 34 50 69 6c cf fa\r\nf2 f4 57 33 0b 0f ac 99 90 97 34 50 69 6c cf fa\r\nc8 1d 19 a9 a1 71 d6 53 53 85 81 60 58 8a 2d f9\r\nc8 1d 19 a9 a1 71 d6 53 7b eb f4 9b da 9a 22 c8\r\n89 1f a3 a8 d1 95 8e 51 19 88 97 f8 b8 f9 41 ab\r\nc2 68 96 f7 18 f2 b4 3f 91 ed 17 97 40 78 99 c6\r\n59 f0 0e 3e e1 09 4f 95 83 ec bc 0f 9b 1e 08 30\r\n0a f3 1f a7 4a 8b 86 61 13 7b 88 5f f2 72 c7 ca\r\n43 2a c8 86 d8 34 c0 b6 d2 c7 df 11 98 4c 59 70\r\n```\r\n\r\nThe Key Expansion of an 256-bit key consisting of null characters:\r\n\r\n``` \r\n00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\r\n00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\r\n62 63 63 63 62 63 63 63 62 63 63 63 62 63 63 63\r\naa fb fb fb aa fb fb fb aa fb fb fb aa fb fb fb\r\n6f 6c 6c cf 0d 0f 0f ac 6f 6c 6c cf 0d 0f 0f ac\r\n7d 8d 8d 6a d7 76 76 91 7d 8d 8d 6a d7 76 76 91\r\n53 54 ed c1 5e 5b e2 6d 31 37 8e a2 3c 38 81 0e\r\n96 8a 81 c1 41 fc f7 50 3c 71 7a 3a eb 07 0c ab\r\n9e aa 8f 28 c0 f1 6d 45 f1 c6 e3 e7 cd fe 62 e9\r\n2b 31 2b df 6a cd dc 8f 56 bc a6 b5 bd bb aa 1e\r\n64 06 fd 52 a4 f7 90 17 55 31 73 f0 98 cf 11 19\r\n6d bb a9 0b 07 76 75 84 51 ca d3 31 ec 71 79 2f\r\ne7 b0 e8 9c 43 47 78 8b 16 76 0b 7b 8e b9 1a 62\r\n74 ed 0b a1 73 9b 7e 25 22 51 ad 14 ce 20 d4 3b\r\n10 f8 0a 17 53 bf 72 9c 45 c9 79 e7 cb 70 63 85\r\n```\r\n\r\n## Implementation: AES Encryption\r\n\r\nTo implement the AES encryption algorithm, we proceed exactly the same\r\nway as for the key expansion, that is, we first implement the basic\r\nhelper functions and then move up to the main loop. The functions take\r\nas parameter a *state*, which is, as already explained, a rectangular\r\n4x4 array of bytes. We won't consider the state as a 2-dimensional\r\narray, but as a 1-dimensional array of length 16.\r\n\r\n### Implementation: subBytes\r\n\r\nThere isn't much to say about this operation, it's a simple\r\nsubstitution with the S-Box value:\r\n\r\n```c \r\nvoid subBytes(unsigned char *state)\r\n{\r\n    int i;\r\n    /* substitute all the values from the state with the value in the SBox\r\n     * using the state value as index for the SBox\r\n     */\r\n    for (i = 0; i \u003c 16; i++)\r\n        state[i] = getSBoxValue(state[i]);\r\n}\r\n```\r\n\r\n### Implementation: shiftRows\r\n\r\nI decided to split this function in two parts, not that it wasn't\r\npossible to do it all in one go, but simply because it was easier to\r\nread and debug. The shiftRows function iterates over all the rows and\r\nthen call shiftRow with the correct offset. shiftRow does nothing but to\r\nshift a 4-byte array by the given offset.\r\n\r\n```c \r\nvoid shiftRows(unsigned char *state)\r\n{\r\n    int i;\r\n    /* iterate over the 4 rows and call shiftRow() with that row */\r\n    for (i = 0; i \u003c 4; i++)\r\n        shiftRow(state+i*4, i);\r\n}\r\n\r\nvoid shiftRow(unsigned char *state, unsigned char nbr)\r\n{\r\n    int i, j;\r\n    unsigned char tmp;\r\n    /* each iteration shifts the row to the left by 1 */\r\n    for (i = 0; i \u003c nbr; i++)\r\n    {\r\n        tmp = state[0];\r\n        for (j = 0; j \u003c 3; j++)\r\n            state[j] = state[j+1];\r\n        state[3] = tmp;\r\n    }\r\n}\r\n```\r\n\r\nThis implementation is the least efficient but the easiest to\r\nunderstand. A very simple improvement would be, since the first row\r\nisn't shifted, to have the iterator in shiftRows start at 1 instead of\r\n0.\r\n\r\n### Implementation: addRoundKey\r\n\r\nThis is the part that involves the roundKey we generate during each\r\niteration. We simply XOR each byte of the key to the respective byte of\r\nthe state.\r\n\r\n```c \r\nvoid addRoundKey(unsigned char *state, unsigned char *roundKey)\r\n{\r\n    int i;\r\n    for (i = 0; i \u003c 16; i++)\r\n        state[i] = state[i] ^ roundKey[i] ;\r\n}\r\n```\r\n\r\n### Implementation: mixColumns\r\n\r\nmixColumns is probably the most difficult operation of the 4. It\r\ninvolves the galois addition and multiplication and processes columns\r\ninstead of rows (which is unfortunate since we use a linear array that\r\nrepresents the rows).\r\n\r\nFirst of all, we need a function that multiplies two number in the\r\ngalois field. I didn't bother to implement this one from scratch and\r\nused the one provided by Sam Trenholme instead:\r\n\r\n```c \r\nunsigned char galois_multiplication(unsigned char a, unsigned char b)\r\n{\r\n    unsigned char p = 0;\r\n    unsigned char counter;\r\n    unsigned char hi_bit_set;\r\n    for(counter = 0; counter \u003c 8; counter++) {\r\n        if((b \u0026 1) == 1)\r\n            p ^= a;\r\n        hi_bit_set = (a \u0026 0x80);\r\n        a \u003c\u003c= 1;\r\n        if(hi_bit_set == 0x80)\r\n            a ^= 0x1b;\r\n        b \u003e\u003e= 1;\r\n    }\r\n    return p;\r\n}\r\n```\r\n\r\nOnce again, I decided to split the function in 2 parts, the first one\r\nwould generate a column and then call mixColumn, which would then apply\r\nthe matrix multiplication.\r\n\r\n```c \r\nvoid mixColumns(unsigned char *state)\r\n{\r\n    int i, j;\r\n    unsigned char column[4];\r\n\r\n    /* iterate over the 4 columns */\r\n    for (i = 0; i \u003c 4; i++)\r\n    {\r\n        /* construct one column by iterating over the 4 rows */\r\n        for (j = 0; j \u003c 4; j++)\r\n        {\r\n            column[j] = state[(j*4)+i];\r\n        }\r\n\r\n        /* apply the mixColumn on one column */\r\n        mixColumn(column);\r\n\r\n        /* put the values back into the state */\r\n        for (j = 0; j \u003c 4; j++)\r\n        {\r\n            state[(j*4)+i] = column[j];\r\n        }\r\n    }\r\n}\r\n```\r\n\r\nThe mixColumn is simply a galois multiplication of the column with the\r\n4x4 matrix provided in the theory. Since an addition corresponds to a\r\nXOR operation and we already have the multiplication function, the\r\nimplementation is rather simple:\r\n\r\n```c \r\nvoid mixColumn(unsigned char *column)\r\n{\r\n    unsigned char cpy[4];\r\n    int i;\r\n    for(i = 0; i \u003c 4; i++)\r\n    {\r\n        cpy[i] = column[i];\r\n    }\r\n    column[0] = galois_multiplication(cpy[0],2) ^\r\n                galois_multiplication(cpy[3],1) ^\r\n                galois_multiplication(cpy[2],1) ^\r\n                galois_multiplication(cpy[1],3);\r\n\r\n    column[1] = galois_multiplication(cpy[1],2) ^\r\n                galois_multiplication(cpy[0],1) ^\r\n                galois_multiplication(cpy[3],1) ^\r\n                galois_multiplication(cpy[2],3);\r\n\r\n    column[2] = galois_multiplication(cpy[2],2) ^\r\n                galois_multiplication(cpy[1],1) ^\r\n                galois_multiplication(cpy[0],1) ^\r\n                galois_multiplication(cpy[3],3);\r\n\r\n    column[3] = galois_multiplication(cpy[3],2) ^\r\n                galois_multiplication(cpy[2],1) ^\r\n                galois_multiplication(cpy[1],1) ^\r\n                galois_multiplication(cpy[0],3);\r\n}\r\n```\r\n\r\nOnce again, this function could be optimized (like using memcpy instead\r\nof the loop) but I left the formulas in their unsimplified form to make\r\nthem easier to read.\r\n\r\n### Implementation: AES round\r\n\r\nAs you can see in the theory, one AES round does nothing but to apply\r\nall four operations on the state consecutively.\r\n\r\n```c \r\nvoid aes_round(unsigned char *state, unsigned char *roundKey)\r\n{\r\n    subBytes(state);\r\n    shiftRows(state);\r\n    mixColumns(state);\r\n    addRoundKey(state, roundKey);\r\n}\r\n```\r\n\r\n### Implementation: the main AES body\r\n\r\nNow that we have all the small functions, the main loop gets really\r\neasy. All we have to do is take the state, the expandedKey and the\r\nnumber of rounds as parameters and then call the operations one after\r\nthe other. A little function called createRoundKey() is used to copy the\r\nnext 16 bytes from the expandedKey into the roundKey, using the special\r\nmapping order.\r\n\r\n```c \r\nvoid createRoundKey(unsigned char *expandedKey, unsigned char *roundKey)\r\n{\r\n    int i,j;\r\n    /* iterate over the columns */\r\n    for (i = 0; i \u003c 4; i++)\r\n    {\r\n        /* iterate over the rows */\r\n        for (j = 0; j \u003c 4; j++)\r\n            roundKey[(i+(j*4))] = expandedKey[(i*4)+j];\r\n    }\r\n}\r\n\r\n\r\nvoid aes_main(unsigned char *state, unsigned char *expandedKey, int nbrRounds)\r\n{\r\n    int i = 0;\r\n\r\n    unsigned char roundKey[16];\r\n\r\n    createRoundKey(expandedKey, roundKey);\r\n    addRoundKey(state, roundKey);\r\n\r\n    for (i = 1; i \u003c nbrRounds; i++) {\r\n        createRoundKey(expandedKey + 16*i, roundKey);\r\n        aes_round(state, roundKey);\r\n    }\r\n\r\n    createRoundKey(expandedKey + 16*nbrRounds, roundKey);\r\n    subBytes(state);\r\n    shiftRows(state);\r\n    addRoundKey(state, roundKey);\r\n}\r\n```\r\n\r\n### Implementation: AES encryption\r\n\r\nFinally, all we have to do is put it all together. Our parameters are\r\nthe input plaintext, the key of size keySize and the output. First, we\r\ncalculate the number of rounds based on they keySize and then the\r\nexpandedKeySize based on the number of rounds. Then we have to map the\r\n16 byte input plaintext in the correct order to the 4x4 byte state (as\r\nexplained above), expand the key using our key schedule, encrypt the\r\nstate using our main AES body and finally unmap the state again in the\r\ncorrect order to get the 16 byte output ciphertext.\r\n\r\nSounds complicated, but you'll see that the code really isn't:\r\n\r\n```c \r\nchar aes_encrypt(unsigned char *input,\r\n                 unsigned char *output,\r\n                 unsigned char *key,\r\n                 enum keySize size)\r\n{\r\n    /* the expanded keySize */\r\n    int expandedKeySize;\r\n\r\n    /* the number of rounds */\r\n    int nbrRounds;\r\n\r\n    /* the expanded key */\r\n    unsigned char *expandedKey;\r\n\r\n    /* the 128 bit block to encode */\r\n    unsigned char block[16];\r\n\r\n    int i,j;\r\n\r\n    /* set the number of rounds */\r\n    switch (size)\r\n    {\r\n        case SIZE_16:\r\n            nbrRounds = 10;\r\n            break;\r\n        case SIZE_24:\r\n            nbrRounds = 12;\r\n            break;\r\n        case SIZE_32:\r\n            nbrRounds = 14;\r\n            break;\r\n        default:\r\n            return UNKNOWN_KEYSIZE;\r\n            break;\r\n    }\r\n\r\n    expandedKeySize = (16*(nbrRounds+1));\r\n    if ((expandedKey = malloc(expandedKeySize * sizeof(char))) == NULL)\r\n    {\r\n        return MEMORY_ALLOCATION_PROBLEM;\r\n    }\r\n\r\n    /* Set the block values, for the block:\r\n     * a0,0 a0,1 a0,2 a0,3\r\n     * a1,0 a1,1 a1,2 a1,3\r\n     * a2,0 a2,1 a2,2 a2,3\r\n     * a3,0 a3,1 a3,2 a3,3\r\n     * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3\r\n     */\r\n\r\n    /* iterate over the columns */\r\n    for (i = 0; i \u003c 4; i++)\r\n    {\r\n        /* iterate over the rows */\r\n        for (j = 0; j \u003c 4; j++)\r\n            block[(i+(j*4))] = input[(i*4)+j];\r\n    }\r\n\r\n    /* expand the key into an 176, 208, 240 bytes key */\r\n    expandKey(expandedKey, key, size, expandedKeySize);\r\n\r\n    /* encrypt the block using the expandedKey */\r\n    aes_main(block, expandedKey, nbrRounds);\r\n\r\n    /* unmap the block again into the output */\r\n    for (i = 0; i \u003c 4; i++)\r\n    {\r\n        /* iterate over the rows */\r\n        for (j = 0; j \u003c 4; j++)\r\n            output[(i*4)+j] = block[(i+(j*4))];\r\n    }\r\n    return 0;\r\n}\r\n```\r\n\r\nIn the above code, UNKNOWN_KEYSIZE and MEMORY_ALLOCATION_PROBLEM are\r\nmacros to some predefined error codes that I can use to check if\r\neverything was ok. The code shouldn't be too complicated and the\r\ncomments should be enough to understand everything.\r\n\r\n## AES Decryption\r\n\r\nIf you managed to understand and implement everything up to this point,\r\nyou shouldn't have any problems getting the decryption to work either.\r\nBasically, we inverse the whole encryption and apply all the operations\r\nbackwards.\r\n\r\nAs the key schedule stays the same, the only operations we need to\r\nimplement are the inversed subBytes, shiftRows and mixColumns, while\r\naddRoundKey stays the same.\r\n\r\nApart from the inversed mixColumns operation, the other operations are\r\ntrivial and I provide you the code.\r\n\r\n```c \r\nvoid invSubBytes(unsigned char *state)\r\n{\r\n    int i;\r\n    /* substitute all the values from the state with the value in the SBox\r\n     * using the state value as index for the SBox\r\n     */\r\n    for (i = 0; i \u003c 16; i++)\r\n        state[i] = getSBoxInvert(state[i]);\r\n}\r\n\r\nvoid invShiftRows(unsigned char *state)\r\n{\r\n    int i;\r\n    /* iterate over the 4 rows and call invShiftRow() with that row */\r\n    for (i = 0; i \u003c 4; i++)\r\n        invShiftRow(state+i*4, i);\r\n}\r\n\r\nvoid invShiftRow(unsigned char *state, unsigned char nbr)\r\n{\r\n    int i, j;\r\n    unsigned char tmp;\r\n    /* each iteration shifts the row to the right by 1 */\r\n    for (i = 0; i \u003c nbr; i++)\r\n    {\r\n        tmp = state[3];\r\n        for (j = 3; j \u003e 0; j--)\r\n            state[j] = state[j-1];\r\n        state[0] = tmp;\r\n    }\r\n}\r\n```\r\n\r\nAs you can see, they are nearly identical to their encryption\r\ncounterpart, except that the rotation this time is to the right and that\r\nwe use the inversed S-Box for the substitution.\r\n\r\nAs for the inversed mixColumns operation, the only difference is the\r\nmultiplication matrix, which is the following:\r\n\r\n``` \r\n14 11 13  9\r\n 9 14 11 13\r\n13  9 14 11\r\n11 13  9 14\r\n```\r\n\r\nAs you can see, all you have to do is change the values in the\r\ngalois_multiplication call with the values from the matrix above, which\r\nresults in the following:\r\n\r\n```c \r\nvoid invMixColumns(unsigned char *state)\r\n{\r\n    int i, j;\r\n    unsigned char column[4];\r\n\r\n    /* iterate over the 4 columns */\r\n    for (i = 0; i \u003c 4; i++)\r\n    {\r\n        /* construct one column by iterating over the 4 rows */\r\n        for (j = 0; j \u003c 4; j++)\r\n        {\r\n            column[j] = state[(j*4)+i];\r\n        }\r\n\r\n        /* apply the invMixColumn on one column */\r\n        invMixColumn(column);\r\n\r\n        /* put the values back into the state */\r\n        for (j = 0; j \u003c 4; j++)\r\n        {\r\n            state[(j*4)+i] = column[j];\r\n        }\r\n    }\r\n}\r\n\r\nvoid invMixColumn(unsigned char *column)\r\n{\r\n    unsigned char cpy[4];\r\n    int i;\r\n    for(i = 0; i \u003c 4; i++)\r\n    {\r\n        cpy[i] = column[i];\r\n    }\r\n    column[0] = galois_multiplication(cpy[0],14) ^\r\n                galois_multiplication(cpy[3],9) ^\r\n                galois_multiplication(cpy[2],13) ^\r\n                galois_multiplication(cpy[1],11);\r\n    column[1] = galois_multiplication(cpy[1],14) ^\r\n                galois_multiplication(cpy[0],9) ^\r\n                galois_multiplication(cpy[3],13) ^\r\n                galois_multiplication(cpy[2],11);\r\n    column[2] = galois_multiplication(cpy[2],14) ^\r\n                galois_multiplication(cpy[1],9) ^\r\n                galois_multiplication(cpy[0],13) ^\r\n                galois_multiplication(cpy[3],11);\r\n    column[3] = galois_multiplication(cpy[3],14) ^\r\n                galois_multiplication(cpy[2],9) ^\r\n                galois_multiplication(cpy[1],13) ^\r\n                galois_multiplication(cpy[0],11);\r\n}\r\n```\r\n\r\nPlease be aware that I could have saved a lot of code repetition by\r\nsimply introducing an additional argument in a common mixColumn\r\noperation, which would use either the matrix for encryption or the\r\nmatrix for decryption (the same is true for the other operations of\r\ncourse).\r\n\r\nOnce we have all our operations inversed, we can specify how one\r\ninversed AES round looks like.\r\n\r\n```c \r\nvoid aes_invRound(unsigned char *state, unsigned char *roundKey)\r\n{\r\n\r\n    invShiftRows(state);\r\n    invSubBytes(state);\r\n    addRoundKey(state, roundKey);\r\n    invMixColumns(state);\r\n}\r\n```\r\n\r\nFinally, the only thing left to do is putting it all together in one\r\ninversed main algorithm. Please note that we use our expanded key\r\nbackwards, starting with the last 16 bytes and then moving towards the\r\nstart.\r\n\r\n```c \r\nvoid aes_invMain(unsigned char *state, unsigned char *expandedKey, int nbrRounds)\r\n{\r\n    int i = 0;\r\n\r\n    unsigned char roundKey[16];\r\n\r\n    createRoundKey(expandedKey + 16*nbrRounds, roundKey);\r\n    addRoundKey(state, roundKey);\r\n\r\n    for (i = nbrRounds-1; i \u003e 0; i--) {\r\n        createRoundKey(expandedKey + 16*i, roundKey);\r\n        aes_invRound(state, roundKey);\r\n    }\r\n\r\n    createRoundKey(expandedKey, roundKey);\r\n    invShiftRows(state);\r\n    invSubBytes(state);\r\n    addRoundKey(state, roundKey);\r\n}\r\n```\r\n\r\nEven though I'm sure that you could figure out the following by\r\nyourself, I want to present you the implementation of the decrypt\r\nfunction, which is identical to the encryption function, except that it\r\ncalls the inversed main function.\r\n\r\n```c \r\nchar aes_decrypt(unsigned char *input,\r\n                 unsigned char *output,\r\n                 unsigned char *key,\r\n                 enum keySize size)\r\n{\r\n    /* the expanded keySize */\r\n    int expandedKeySize;\r\n\r\n    /* the number of rounds */\r\n    int nbrRounds;\r\n\r\n    /* the expanded key */\r\n    unsigned char *expandedKey;\r\n\r\n    /* the 128 bit block to decode */\r\n    unsigned char block[16];\r\n\r\n    int i,j;\r\n\r\n    /* set the number of rounds */\r\n    switch (size)\r\n    {\r\n        case SIZE_16:\r\n            nbrRounds = 10;\r\n            break;\r\n        case SIZE_24:\r\n            nbrRounds = 12;\r\n            break;\r\n        case SIZE_32:\r\n            nbrRounds = 14;\r\n            break;\r\n        default:\r\n            return UNKNOWN_KEYSIZE;\r\n            break;\r\n    }\r\n\r\n    expandedKeySize = (16*(nbrRounds+1));\r\n    if ((expandedKey = malloc(expandedKeySize * sizeof(char))) == NULL)\r\n    {\r\n        return MEMORY_ALLOCATION_PROBLEM;\r\n    }\r\n\r\n    /* Set the block values, for the block:\r\n     * a0,0 a0,1 a0,2 a0,3\r\n     * a1,0 a1,1 a1,2 a1,3\r\n     * a2,0 a2,1 a2,2 a2,3\r\n     * a3,0 a3,1 a3,2 a3,3\r\n     * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3\r\n     */\r\n\r\n    /* iterate over the columns */\r\n    for (i = 0; i \u003c 4; i++)\r\n    {\r\n        /* iterate over the rows */\r\n        for (j = 0; j \u003c 4; j++)\r\n            block[(i+(j*4))] = input[(i*4)+j];\r\n    }\r\n\r\n    /* expand the key into an 176, 208, 240 bytes key */\r\n    expandKey(expandedKey, key, size, expandedKeySize);\r\n\r\n    /* decrypt the block using the expandedKey */\r\n    aes_invMain(block, expandedKey, nbrRounds);\r\n\r\n    /* unmap the block again into the output */\r\n    for (i = 0; i \u003c 4; i++)\r\n    {\r\n        /* iterate over the rows */\r\n        for (j = 0; j \u003c 4; j++)\r\n            output[(i*4)+j] = block[(i+(j*4))];\r\n    }\r\n}\r\n```\r\n\r\nThis is the end of our Advanced Encryption Standard Implementation, all\r\nthat is left is to take our finished AES functions and use them inside a\r\n*block cipher modes of operation* to be able to encrypt/decrypt messages\r\nof any size.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fm3y54m%2Faes-in-c","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fm3y54m%2Faes-in-c","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fm3y54m%2Faes-in-c/lists"}