├── LICENSE ├── LICENSE-OCB ├── README.md ├── composer.json ├── lib ├── CBC.php ├── CFB.php ├── CTR.php ├── Cipher.php ├── Context │ ├── CBC │ │ ├── Context.php │ │ ├── DecryptionContext.php │ │ └── EncryptionContext.php │ ├── CFB │ │ ├── Context.php │ │ ├── DecryptionContext.php │ │ └── EncryptionContext.php │ ├── CTR │ │ ├── Context.php │ │ ├── DecryptionContext.php │ │ └── EncryptionContext.php │ ├── GCM │ │ ├── Context.php │ │ ├── DecryptionContext.php │ │ └── EncryptionContext.php │ ├── OCB │ │ ├── Context.php │ │ ├── DecryptionContext.php │ │ └── EncryptionContext.php │ └── OFB │ │ ├── Context.php │ │ ├── DecryptionContext.php │ │ └── EncryptionContext.php ├── ECB.php ├── Exception.php ├── Exception │ ├── AuthenticationException.php │ ├── BlockLengthException.php │ ├── IVLengthException.php │ ├── InvalidContextException.php │ ├── InvalidPaddingException.php │ └── KeyLengthException.php ├── GCM.php ├── Key.php ├── OCB.php ├── OFB.php ├── Padding │ ├── ANSIX923.php │ ├── ISOIEC7816.php │ ├── PKCS7.php │ └── Scheme.php └── constants.php ├── phpunit.xml.dist └── test ├── CBC ├── CBCGFSbox128Test.php ├── CBCGFSbox192Test.php ├── CBCGFSbox256Test.php ├── CBCKeySbox128Test.php ├── CBCKeySbox192Test.php ├── CBCKeySbox256Test.php ├── CBCMCT128Test.php ├── CBCMCT192Test.php ├── CBCMCT256Test.php ├── CBCMMT128Test.php ├── CBCMMT192Test.php ├── CBCMMT256Test.php ├── CBCVarKey128Test.php ├── CBCVarKey192Test.php ├── CBCVarKey256Test.php ├── CBCVarTxt128Test.php ├── CBCVarTxt192Test.php └── CBCVarTxt256Test.php ├── CFB ├── CFB128GFSbox128Test.php ├── CFB128GFSbox192Test.php ├── CFB128GFSbox256Test.php ├── CFB128KeySbox128Test.php ├── CFB128KeySbox192Test.php ├── CFB128KeySbox256Test.php ├── CFB128MCT128Test.php ├── CFB128MCT192Test.php ├── CFB128MCT256Test.php ├── CFB128MMT128Test.php ├── CFB128MMT192Test.php ├── CFB128MMT256Test.php ├── CFB128VarKey128Test.php ├── CFB128VarKey192Test.php ├── CFB128VarKey256Test.php ├── CFB128VarTxt128Test.php ├── CFB128VarTxt192Test.php └── CFB128VarTxt256Test.php ├── CTR ├── CTR128Test.php ├── CTR192Test.php └── CTR256Test.php ├── ECB ├── ECBGFSbox128Test.php ├── ECBGFSbox192Test.php ├── ECBGFSbox256Test.php ├── ECBKeySbox128Test.php ├── ECBKeySbox192Test.php ├── ECBKeySbox256Test.php ├── ECBMCT128Test.php ├── ECBMCT192Test.php ├── ECBMCT256Test.php ├── ECBMMT128Test.php ├── ECBMMT192Test.php ├── ECBMMT256Test.php ├── ECBVarKey128Test.php ├── ECBVarKey192Test.php ├── ECBVarKey256Test.php ├── ECBVarTxt128Test.php ├── ECBVarTxt192Test.php └── ECBVarTxt256Test.php ├── OCB └── OCBTest.php ├── OFB ├── OFBGFSbox128Test.php ├── OFBGFSbox192Test.php ├── OFBGFSbox256Test.php ├── OFBKeySbox128Test.php ├── OFBKeySbox192Test.php ├── OFBKeySbox256Test.php ├── OFBMCT128Test.php ├── OFBMCT192Test.php ├── OFBMCT256Test.php ├── OFBMMT128Test.php ├── OFBMMT192Test.php ├── OFBMMT256Test.php ├── OFBVarKey128Test.php ├── OFBVarKey192Test.php ├── OFBVarKey256Test.php ├── OFBVarTxt128Test.php ├── OFBVarTxt192Test.php └── OFBVarTxt256Test.php └── Padding ├── ANSIX923Test.php ├── ISOIEC7816Test.php └── PKCS7Test.php /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Leigh T 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LICENSE-OCB: -------------------------------------------------------------------------------- 1 | OCB is a patent encumbered cipher mode. 2 | 3 | The following is taken from http://www.cs.ucdavis.edu/~rogaway/ocb/license.htm (2016-04-8) 4 | 5 | -------------------------------------------------------------------------------- 6 | 7 | While there are patents that cover OCB, I have decided to freely license my IP for “most” software. Note that the summaries below are non-binding summary of legal documents (clice on each link for the legal document). The parameters of the license are specified in the license document and that document is controlling. 8 | 9 | License 1 — License for Open-Source Software Implementations of OCB (Jan 9, 2013) 10 | Under this license, you are authorized to make, use, and distribute open-source software implementations of OCB. This license terminates for you if you sue someone over their open-source software implementation of OCB claiming that you have a patent covering their implementation. 11 | 12 | License 2 — General License for Non-Military Software Implementations OCB (Jan 10, 2013). 13 | This license does not authorize any military use of OCB. Aside from military uses, you are authorized to make, use, and distribute (1) any software implementation of OCB and (2) non-software implementations of OCB for noncommercial or research purposes. You are required to include notice of this license to users of your work so that they are aware of the prohibition against military use. This license terminates for you if you sue someone over an implementation of OCB authorized by this license claiming that you have a patent covering their implementation. 14 | 15 | License 3 — Patent License for OpenSSL (Nov 13, 2013). 16 | This license was provided at the request of the OpenSSL Software Foundation to specifically authorize use of OCB in OpenSSL. 17 | 18 | An interesting provision of licenses 1 and 2 is that the license grant to a party terminates if that party sues someone else over their use of OCB. This is a legal scholar’s clever approach for me to try to discourage others from suing you for using OCB. 19 | 20 | If you have a use for OCB in mind that is not covered by the above grants but for which you believe that a paid-up license would be inappropriate, please write to me to explain. Otherwise, I will license OCB under fair, reasonable, and non-discriminatory terms. Here is an old patent-assurance letter I wrote for the IEEE promising this. I expect licensees to pay a small, one-time fee. I intend that no solvent company should find licensing to be a significant burden. To inquire about a license other than those above, just send an email to rogaway@cs.ucdavis.edu 21 | 22 | -------------------------------------------------------------------------------- 23 | 24 | I am publishing my implementation of this software under License 1. 25 | 26 | If you use my implementation in your own software, you must ensure you adhere to one of the above licenses. 27 | 28 | The full text of License 1 is reproduced below. 29 | 30 | -------------------------------------------------------------------------------- 31 | 32 | License for Open Source Software Implementations of OCB 33 | 34 | January 9, 2013 35 | 36 | 1 Definitions 37 | 38 | 1.1 "Licensor" means Phillip Rogaway. 39 | 40 | 1.2 "Licensed Patents" means any patent that claims priority to United States Patent 41 | Application No. 09/918,615 entitled "Method and Apparatus for Facilitating 42 | Efficient Authenticated Encryption," and any utility, divisional, provisional, 43 | continuation, continuations-in-part, reexamination, reissue, or foreign counterpart 44 | patents that may issue with respect to the aforesaid patent application. This 45 | includes, but is not limited to, United States Patent No. 7,046,802; United States 46 | Patent No. 7,200,227; United States Patent No. 7,949,129; United States Patent 47 | No. 8,321,675; and any patent that issues out of United States Patent Application 48 | No. 13/669,114.1.3 "Use" means any practice of any invention claimed in the Licensed Patents. 49 | 50 | 1.4 "Software Implementation" means any practice of any invention claimed in the 51 | Licensed Patents that takes the form of software executing on a user- 52 | programmable, general-purpose computer or that takes the form of a computer- 53 | readable medium storing such software. Software Implementation does not 54 | include, for example, application-specific integrated circuits (ASICs), field- 55 | programmable gate arrays (FPGAs), embedded systems, or IP cores. 56 | 57 | 1.5 "Open Source Software" means software whose source code is published and 58 | made available for inspection and use by anyone because either (a) the source code 59 | is subject to a license that permits recipients to copy, modify, and distribute the 60 | source code without payment of fees or royalties, or (b) the source code is in the 61 | public domain, including code released for public use through a CC0 waiver. All 62 | licenses certified by the Open Source Initiative at opensource.org as of January 9, 63 | 2013 and all Creative Commons licenses identified on the creativecommons.org 64 | website as of January 9, 2013, including the Public License Fallback of the CC0 65 | waiver, satisfy these requirements for the purposes of this license. 66 | 67 | 1.6 "Open Source Software Implementation" means a Software Implementation in 68 | which the software implicating the Licensed Patents is Open Source Software. 69 | Open Source Software Implementation does not include any Software 70 | Implementation in which the software implicating the Licensed Patents is 71 | combined, so as to form a larger program, with software that is not Open Source 72 | Software. 73 | 74 | 2 License Grant 75 | 76 | 2.1 License. Subject to your compliance with the terms of this license, including the 77 | restriction set forth in Section 2.2, Licensor hereby grants to you a perpetual, 78 | worldwide, non-exclusive, non-transferable, non-sublicenseable, no-charge, 79 | royalty-free, irrevocable license to practice any invention claimed in the Licensed 80 | Patents in any Open Source Software Implementation. 81 | 82 | 2.2 Restriction. If you or your affiliates institute patent litigation (including, but 83 | not limited to, a cross-claim or counterclaim in a lawsuit) against any entity 84 | alleging that any Use authorized by this license infringes another patent, then any 85 | rights granted to you under this license automatically terminate as of the date such 86 | litigation is filed. 87 | 88 | 3 Disclaimer 89 | 90 | YOUR USE OF THE LICENSED PATENTS IS AT YOUR OWN RISK AND 91 | UNLESS REQUIRED BY APPLICABLE LAW, LICENSOR MAKES NO 92 | REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE 93 | LICENSED PATENTS OR ANY PRODUCT EMBODYING ANY LICENSED 94 | PATENT, EXPRESS OR IMPLIED, STATUTORY OR OTHERWISE, 95 | INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, 96 | MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 97 | NONINFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY 98 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT 99 | OR OTHERWISE, ARISING FROM OR RELATED TO ANY USE OF THE 100 | LICENSED PATENTS, INCLUDING, WITHOUT LIMITATION, DIRECT, 101 | INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR SPECIAL 102 | DAMAGES, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY 103 | OF SUCH DAMAGES PRIOR TO SUCH AN OCCURRENCE. 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AES in PHP 2 | ========== 3 | 4 | This library contains pure PHP implementations of the AES block cipher and several modes of operation based on it. 5 | 6 | **These are toy implementations for fun/education and come with exactly zero security guarantees.** 7 | 8 | The underlying block cipher variation is chosen automatically based on the length of the supplied key. 9 | 10 | - AES-128 is used when a 16 byte key is supplied 11 | - AES-192 is used when a 24 byte key is supplied 12 | - AES-256 is used when a 32 byte key is supplied 13 | 14 | It is the responsibility of the user to ensure that the message is properly padded when using a block mode. If the supplied message is not a multiple of 16 bytes in length an exception will be thrown. 15 | 16 | The following block chaining modes are available: 17 | 18 | - ECB 19 | - CBC 20 | 21 | The following stream cipher modes are available: 22 | 23 | - CTR 24 | - CFB 25 | - OFB 26 | 27 | The following AEAD modes are available: 28 | 29 | - OCB 30 | - GCM 31 | 32 | The following padding schemes are available: 33 | 34 | - PKCS7 35 | - ANSI X.923 36 | - ISO/IEC 7816 37 | 38 | ### Usage: 39 | 40 | All modes have one-shot `encrypt()` and `decrypt()` methods which accept different parameters depending on the mode. 41 | 42 | Example: 43 | 44 | ```php 45 | $key = new AES\Key('abcdefghijklmnop'); 46 | $nonce = 'abcdefghijklmnop'; 47 | 48 | $ctr = new AES\CTR; 49 | $ciphertext = $ctr->encrypt($key, $nonce, $plaintext); 50 | ``` 51 | 52 | All modes also have streaming capabilities allowing encryption/decryption to be done in chunks. 53 | 54 | To use any mode of operation like this an appropriate `Context` needs to be initialised first. The context keeps track of state allowing longer messages to be processed in multiple blocks. 55 | 56 | Separate contexts are required for encryption and decryption. 57 | 58 | Example: 59 | ```php 60 | $key = new AES\Key('abcdefghijklmnop'); 61 | $nonce = 'abcdefghijklmnop'; 62 | 63 | $ctr = new AES\CTR; 64 | $encryptionContext = $ctr->initEncryption($key, $nonce); 65 | 66 | $ciphertext = $ctr->streamEncrypt($encryptionContext, $plaintext0); 67 | $ciphertext .= $ctr->streamEncrypt($encryptionContext, $plaintext1); 68 | ``` 69 | 70 | AEAD modes are slightly more complicated. 71 | 72 | A few caveats: 73 | - OCB when streaming can process AAD at any time 74 | - GCM when streaming has to process AAD first 75 | - GCM only validates the tag prior to decryption when using the one-shot `decrypt()`. It can't do this with `streamDecrypt()` because it doesn't have all of the data yet. 76 | - GCM has a significant initialisation overhead (time and memory) which is key dependant. If you plan to re-use the same key with different nonces you can use the `reInit()` method 77 | - OCB and GCM one-shot `encrypt()` returns an array of `[$ciphertext, $tag]` 78 | - OCB and GCM when streaming will output aligned to 16-byte blocks and `finalise()` returns the final piece of ciphertext/plaintext. // TODO: Fix for GCM, OCB doesn't seem possible 79 | 80 | Example stream usage: 81 | 82 | ```php 83 | $key = new AES\Key('abcdefghijklmnop'); 84 | $nonce = 'abcdefghijkl'; // 12 byte nonce for GCM 85 | $aad = 'Hello' 86 | 87 | $gcm = new AES\GCM; 88 | $encryptionContext = $gcm->initEncryption($key, $nonce); 89 | 90 | $gcm->aad($aad0); 91 | $gcm->aad($aad1); 92 | 93 | $ciphertext = $gcm->streamEncrypt($encryptionContext, $plaintext0); 94 | $ciphertext .= $gcm->streamEncrypt($encryptionContext, $plaintext1); 95 | $ciphertext .= $gcm->finalise($context); 96 | 97 | // $gcm->verify($context, $tag); // If decrypting 98 | $tag = $gcm->tag($context); 99 | ``` 100 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leigh/php-aes", 3 | "homepage": "https://github.com/lt/PHP-AES", 4 | "description": "Pure PHP implementation of the AES cipher.", 5 | "require": { 6 | "php-64bit": ">=7.0" 7 | }, 8 | "require-dev": { 9 | "phpunit/phpunit": "~5.0" 10 | }, 11 | "autoload": { 12 | "psr-4": { 13 | "AES\\": "lib" 14 | }, 15 | "files": [ 16 | "lib/constants.php" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/CBC.php: -------------------------------------------------------------------------------- 1 | key = $key; 21 | $context->iv = $iv; 22 | } 23 | 24 | function initEncryption(Key $key, string $iv): EncryptionContext 25 | { 26 | $context = new EncryptionContext; 27 | $this->init($context, $key, $iv); 28 | return $context; 29 | } 30 | 31 | function initDecryption(Key $key, string $iv): DecryptionContext 32 | { 33 | $context = new DecryptionContext; 34 | $this->init($context, $key, $iv); 35 | return $context; 36 | } 37 | 38 | function streamEncrypt(EncryptionContext $context, string $message): string 39 | { 40 | $ciphertext = ''; 41 | 42 | $iv = $context->iv; 43 | 44 | $messageOffset = 0; 45 | $blockCount = strlen($message) >> 4; 46 | while ($blockCount--) { 47 | $messageBlock = substr($message, $messageOffset, 16); 48 | $encryptedBlock = $this->encryptBlock($context->key, $messageBlock ^ $iv); 49 | $ciphertext .= $encryptedBlock; 50 | $iv = $encryptedBlock; 51 | 52 | $messageOffset += 16; 53 | } 54 | 55 | $context->iv = $iv; 56 | 57 | return $ciphertext; 58 | } 59 | 60 | function streamDecrypt(DecryptionContext $context, string $message): string 61 | { 62 | $plaintext = ''; 63 | 64 | $iv = $context->iv; 65 | 66 | $messageOffset = 0; 67 | $blockCount = strlen($message) >> 4; 68 | while ($blockCount--) { 69 | $messageBlock = substr($message, $messageOffset, 16); 70 | $decryptedBlock = $this->decryptBlock($context->key, $messageBlock) ^ $iv; 71 | $plaintext .= $decryptedBlock; 72 | $iv = $messageBlock; 73 | 74 | $messageOffset += 16; 75 | } 76 | 77 | $context->iv = $iv; 78 | 79 | return $plaintext; 80 | } 81 | 82 | function encrypt(Key $key, string $iv, string $message): string 83 | { 84 | $context = $this->initEncryption($key, $iv); 85 | return $this->streamEncrypt($context, $message); 86 | } 87 | 88 | function decrypt(Key $key, string $iv, string $message): string 89 | { 90 | $context = $this->initDecryption($key, $iv); 91 | return $this->streamDecrypt($context, $message); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/CFB.php: -------------------------------------------------------------------------------- 1 | key = $key; 21 | $context->iv = $iv; 22 | } 23 | 24 | function initEncryption(Key $key, string $iv): EncryptionContext 25 | { 26 | $context = new EncryptionContext; 27 | $this->init($context, $key, $iv); 28 | return $context; 29 | } 30 | 31 | function initDecryption(Key $key, string $iv): DecryptionContext 32 | { 33 | $context = new DecryptionContext; 34 | $this->init($context, $key, $iv); 35 | return $context; 36 | } 37 | 38 | function streamEncrypt(EncryptionContext $context, string $message): string 39 | { 40 | $keyStream = $context->keyStream; 41 | 42 | // Since this is a stream mode the output doesn't have to be aligned to block boundaries. 43 | // However we only get a new IV when a block (i.e. keyStream) has been fully consumed. 44 | 45 | // It's possible that it may take several calls (i.e. short messages) to consume the block, 46 | // so the IV is built up as we go. 47 | 48 | // The len(iv) + len(keyStream) should always be equal to 16 49 | $ciphertext = $message ^ $keyStream; 50 | $iv = $context->iv . $ciphertext; 51 | 52 | // if the message was short and didn't consume the remaining 53 | // keyStream then 0 bytes are required and the loop is skipped 54 | $messageOffset = strlen($ciphertext); 55 | $bytesRequired = strlen($message) - $messageOffset; 56 | $bytesOver = $bytesRequired % 16; 57 | 58 | $blockCount = ($bytesRequired >> 4) + ($bytesOver > 0); 59 | while ($blockCount-- > 0) { 60 | $messageBlock = substr($message, $messageOffset, 16); 61 | $keyStream = $this->encryptBlock($context->key, $iv); 62 | 63 | // len(iv) can be less than 16 on the last block 64 | $encryptedBlock = $keyStream ^ $messageBlock; 65 | $iv = $encryptedBlock; 66 | $ciphertext .= $encryptedBlock; 67 | 68 | $messageOffset += 16; 69 | } 70 | 71 | $context->keyStream = substr($keyStream, strlen($iv)); 72 | $context->iv = $iv; 73 | 74 | return $ciphertext; 75 | } 76 | 77 | function streamDecrypt(DecryptionContext $context, string $message): string 78 | { 79 | $keyStream = $context->keyStream; 80 | 81 | // Similar to encrypt, we only get a new iv for each block-aligned 82 | // piece of ciphertext, so we need to build it as we go in case of 83 | // many calls with small messages 84 | $plaintext = $message ^ $keyStream; 85 | $messageOffset = strlen($plaintext); 86 | $iv = $context->iv . substr($message, 0, $messageOffset); 87 | 88 | $bytesRequired = strlen($message) - $messageOffset; 89 | $bytesOver = $bytesRequired % 16; 90 | 91 | $blockCount = ($bytesRequired >> 4) + ($bytesOver > 0); 92 | while ($blockCount--) { 93 | $messageBlock = substr($message, $messageOffset, 16); 94 | $keyStream = $this->encryptBlock($context->key, $iv); 95 | 96 | $decryptedBlock = $keyStream ^ $messageBlock; 97 | $iv = $messageBlock; 98 | $plaintext .= $decryptedBlock; 99 | 100 | $messageOffset += 16; 101 | } 102 | 103 | $context->keyStream = substr($keyStream, strlen($iv)); 104 | $context->iv = $iv; 105 | 106 | return $plaintext; 107 | } 108 | 109 | function encrypt(Key $key, string $iv, string $message): string 110 | { 111 | $context = $this->initEncryption($key, $iv); 112 | return $this->streamEncrypt($context, $message); 113 | } 114 | 115 | function decrypt(Key $key, string $iv, string $message): string 116 | { 117 | $context = $this->initDecryption($key, $iv); 118 | return $this->streamDecrypt($context, $message); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /lib/CTR.php: -------------------------------------------------------------------------------- 1 | key = $key; 21 | $context->nonce = array_values(unpack('N4', $nonce)); 22 | } 23 | 24 | function initEncryption(Key $key, string $nonce): EncryptionContext 25 | { 26 | $context = new EncryptionContext; 27 | $this->init($context, $key, $nonce); 28 | return $context; 29 | } 30 | 31 | function initDecryption(Key $key, string $nonce): DecryptionContext 32 | { 33 | $context = new DecryptionContext; 34 | $this->init($context, $key, $nonce); 35 | return $context; 36 | } 37 | 38 | private function transcrypt(Context $context, string $message): string 39 | { 40 | $nonce = $context->nonce; 41 | $keyStream = $context->keyStream; 42 | 43 | $bytesRequired = strlen($message) - strlen($keyStream); 44 | $bytesOver = $bytesRequired % 16; 45 | 46 | $blockCount = ($bytesRequired >> 4) + ($bytesOver > 0); 47 | while ($blockCount-- > 0) { 48 | $keyStream .= $this->encryptBlock($context->key, pack('N4', ...$nonce)); 49 | 50 | for($i = 3; $i >= 0; $i--) { 51 | $nonce[$i]++; 52 | $nonce[$i] &= 0xffffffff; 53 | if ($nonce[$i]) { 54 | break; 55 | } 56 | } 57 | } 58 | 59 | $context->keyStream = substr($keyStream, $bytesRequired); 60 | $context->nonce = $nonce; 61 | 62 | return $message ^ $keyStream; 63 | } 64 | 65 | function streamEncrypt(EncryptionContext $ctx, string $message): string 66 | { 67 | return $this->transcrypt($ctx, $message); 68 | } 69 | 70 | function streamDecrypt(DecryptionContext $ctx, string $message): string 71 | { 72 | return $this->transcrypt($ctx, $message); 73 | } 74 | 75 | function encrypt(Key $key, string $nonce, string $message): string 76 | { 77 | $context = $this->initEncryption($key, $nonce); 78 | return $this->streamEncrypt($context, $message); 79 | } 80 | 81 | function decrypt(Key $key, string $nonce, string $message): string 82 | { 83 | $context = $this->initDecryption($key, $nonce); 84 | return $this->streamDecrypt($context, $message); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/Cipher.php: -------------------------------------------------------------------------------- 1 | > 24 ] ^ 12 | MIXCOLUMNS_1[$b >> 16 & 0xff] ^ 13 | MIXCOLUMNS_2[$c >> 8 & 0xff] ^ 14 | MIXCOLUMNS_3[$d & 0xff]; 15 | } 16 | 17 | private function mixColumnsInverse(int $a, int $b, int $c, int $d): int 18 | { 19 | return MIXCOLUMNS_INVERSE_0[$a >> 24 ] ^ 20 | MIXCOLUMNS_INVERSE_1[$b >> 16 & 0xff] ^ 21 | MIXCOLUMNS_INVERSE_2[$c >> 8 & 0xff] ^ 22 | MIXCOLUMNS_INVERSE_3[$d & 0xff]; 23 | } 24 | 25 | private function subBytes(int $a, int $b, int $c, int $d): int 26 | { 27 | return (SUBBYTES[$a >> 24 ] << 24) | 28 | (SUBBYTES[$b >> 16 & 0xff] << 16) | 29 | (SUBBYTES[$c >> 8 & 0xff] << 8) | 30 | SUBBYTES[$d & 0xff]; 31 | } 32 | 33 | private function subBytesInverse(int $a, int $b, int $c, int $d): int 34 | { 35 | return (SUBBYTES_INVERSE[$a >> 24 ] << 24) | 36 | (SUBBYTES_INVERSE[$b >> 16 & 0xff] << 16) | 37 | (SUBBYTES_INVERSE[$c >> 8 & 0xff] << 8) | 38 | SUBBYTES_INVERSE[$d & 0xff]; 39 | } 40 | 41 | protected function encryptBlock(Key $key, string $block): string 42 | { 43 | if (strlen($block) !== 16) { 44 | throw new BlockLengthException; 45 | } 46 | 47 | $k = $key->encryptionKey(); 48 | 49 | list(, $a, $b, $c, $d) = unpack('N4', $block); 50 | 51 | $a ^= $k[0]; 52 | $b ^= $k[1]; 53 | $c ^= $k[2]; 54 | $d ^= $k[3]; 55 | 56 | $i = 4; 57 | $rounds = ($key->bits() >> 5) + 5; 58 | while ($rounds--) { 59 | list($a, $b, $c, $d) = [ 60 | $this->mixColumns($a, $b, $c, $d) ^ $k[$i++], 61 | $this->mixColumns($b, $c, $d, $a) ^ $k[$i++], 62 | $this->mixColumns($c, $d, $a, $b) ^ $k[$i++], 63 | $this->mixColumns($d, $a, $b, $c) ^ $k[$i++] 64 | ]; 65 | } 66 | 67 | return pack('N4', 68 | $this->subBytes($a, $b, $c, $d) ^ $k[56], 69 | $this->subBytes($b, $c, $d, $a) ^ $k[57], 70 | $this->subBytes($c, $d, $a, $b) ^ $k[58], 71 | $this->subBytes($d, $a, $b, $c) ^ $k[59] 72 | ); 73 | } 74 | 75 | protected function decryptBlock(Key $key, string $block): string 76 | { 77 | if (strlen($block) !== 16) { 78 | throw new BlockLengthException; 79 | } 80 | 81 | $k = $key->decryptionKey(); 82 | 83 | list(, $a, $b, $c, $d) = unpack('N4', $block); 84 | 85 | $d ^= $k[59]; 86 | $c ^= $k[58]; 87 | $b ^= $k[57]; 88 | $a ^= $k[56]; 89 | 90 | $i = ($key->bits() >> 3) + 23; 91 | while ($i > 3) { 92 | list($d, $c, $b, $a) = [ 93 | $this->mixColumnsInverse($d, $c, $b, $a) ^ $k[$i--], 94 | $this->mixColumnsInverse($c, $b, $a, $d) ^ $k[$i--], 95 | $this->mixColumnsInverse($b, $a, $d, $c) ^ $k[$i--], 96 | $this->mixColumnsInverse($a, $d, $c, $b) ^ $k[$i--], 97 | ]; 98 | } 99 | 100 | return pack('N4', 101 | $this->subBytesInverse($a, $d, $c, $b) ^ $k[0], 102 | $this->subBytesInverse($b, $a, $d, $c) ^ $k[1], 103 | $this->subBytesInverse($c, $b, $a, $d) ^ $k[2], 104 | $this->subBytesInverse($d, $c, $b, $a) ^ $k[3] 105 | ); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lib/Context/CBC/Context.php: -------------------------------------------------------------------------------- 1 | > 4; 13 | while ($blockCount--) { 14 | $messageBlock = substr($message, $messageOffset, 16); 15 | $ciphertext .= $this->encryptBlock($key, $messageBlock); 16 | 17 | $messageOffset += 16; 18 | } 19 | 20 | return $ciphertext; 21 | } 22 | 23 | function decrypt(Key $key, string $message): string 24 | { 25 | $plaintext = ''; 26 | 27 | $messageOffset = 0; 28 | $blockCount = strlen($message) >> 4; 29 | while ($blockCount--) { 30 | $messageBlock = substr($message, $messageOffset, 16); 31 | $plaintext .= $this->decryptBlock($key, $messageBlock); 32 | 33 | $messageOffset += 16; 34 | } 35 | 36 | return $plaintext; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/Exception.php: -------------------------------------------------------------------------------- 1 | generate128($key); 20 | break; 21 | case 192: 22 | $this->generate192($key); 23 | break; 24 | case 256: 25 | $this->generate256($key); 26 | break; 27 | default: 28 | throw new KeyLengthException; 29 | } 30 | 31 | $this->bits = $bits; 32 | } 33 | 34 | function bits(): int 35 | { 36 | return $this->bits; 37 | } 38 | 39 | function encryptionKey(): array 40 | { 41 | return $this->encryptionKey; 42 | } 43 | 44 | function decryptionKey(): array 45 | { 46 | return $this->decryptionKey; 47 | } 48 | 49 | private function encryptionKeyRound(int $k, int $rc): int 50 | { 51 | return (SUBBYTES[$k & 0xff] << 8) | 52 | (SUBBYTES[$k >> 8 & 0xff] << 16) | 53 | ((SUBBYTES[$k >> 16 & 0xff] ^ $rc) << 24) | 54 | SUBBYTES[$k >> 24 ]; 55 | } 56 | 57 | private function decryptionKeyRound(int $k): int 58 | { 59 | return MIXCOLUMNS_INVERSE_0[SUBBYTES[$k >> 24 ]] ^ 60 | MIXCOLUMNS_INVERSE_1[SUBBYTES[$k >> 16 & 0xff]] ^ 61 | MIXCOLUMNS_INVERSE_2[SUBBYTES[$k >> 8 & 0xff]] ^ 62 | MIXCOLUMNS_INVERSE_3[SUBBYTES[$k & 0xff]]; 63 | } 64 | 65 | private function generate128(string $key) 66 | { 67 | list(, $k0, $k1, $k2, $k3) = unpack('N4', $key); 68 | 69 | $encryptionKey = 70 | $decryptionKey = [$k0, $k1, $k2, $k3]; 71 | 72 | for ($i = 4, $rc = 1; $i < 40; $rc = ($rc << 1) % 0xe5) { 73 | $encryptionKey[$i ] = $k0 ^= $this->encryptionKeyRound($k3, $rc); 74 | $decryptionKey[$i++] = $this->decryptionKeyRound($k0); 75 | $encryptionKey[$i ] = $k1 ^= $k0; 76 | $decryptionKey[$i++] = $this->decryptionKeyRound($k1); 77 | $encryptionKey[$i ] = $k2 ^= $k1; 78 | $decryptionKey[$i++] = $this->decryptionKeyRound($k2); 79 | $encryptionKey[$i ] = $k3 ^= $k2; 80 | $decryptionKey[$i++] = $this->decryptionKeyRound($k3); 81 | } 82 | 83 | $encryptionKey[56] = $decryptionKey[56] = $k0 ^= $this->encryptionKeyRound($k3, 0x36); 84 | $encryptionKey[57] = $decryptionKey[57] = $k1 ^= $k0; 85 | $encryptionKey[58] = $decryptionKey[58] = $k2 ^= $k1; 86 | $encryptionKey[59] = $decryptionKey[59] = $k3 ^ $k2; 87 | 88 | $this->encryptionKey = $encryptionKey; 89 | $this->decryptionKey = $decryptionKey; 90 | } 91 | 92 | private function generate192(string $key) 93 | { 94 | list(, $k0, $k1, $k2, $k3, $k4, $k5) = unpack('N6', $key); 95 | 96 | $encryptionKey = [$k0, $k1, $k2, $k3, $k4, $k5]; 97 | $decryptionKey = [ 98 | $k0, $k1, $k2, $k3, 99 | $this->decryptionKeyRound($k4), 100 | $this->decryptionKeyRound($k5) 101 | ]; 102 | 103 | for ($i = 6, $rc = 1; $i < 48; $rc <<= 1) { 104 | $encryptionKey[$i ] = $k0 ^= $this->encryptionKeyRound($k5, $rc); 105 | $decryptionKey[$i++] = $this->decryptionKeyRound($k0); 106 | $encryptionKey[$i ] = $k1 ^= $k0; 107 | $decryptionKey[$i++] = $this->decryptionKeyRound($k1); 108 | $encryptionKey[$i ] = $k2 ^= $k1; 109 | $decryptionKey[$i++] = $this->decryptionKeyRound($k2); 110 | $encryptionKey[$i ] = $k3 ^= $k2; 111 | $decryptionKey[$i++] = $this->decryptionKeyRound($k3); 112 | $encryptionKey[$i ] = $k4 ^= $k3; 113 | $decryptionKey[$i++] = $this->decryptionKeyRound($k4); 114 | $encryptionKey[$i ] = $k5 ^= $k4; 115 | $decryptionKey[$i++] = $this->decryptionKeyRound($k5); 116 | } 117 | 118 | $encryptionKey[56] = $decryptionKey[56] = $k0 ^= $this->encryptionKeyRound($k5, 0x80); 119 | $encryptionKey[57] = $decryptionKey[57] = $k1 ^= $k0; 120 | $encryptionKey[58] = $decryptionKey[58] = $k2 ^= $k1; 121 | $encryptionKey[59] = $decryptionKey[59] = $k3 ^ $k2; 122 | 123 | $this->encryptionKey = $encryptionKey; 124 | $this->decryptionKey = $decryptionKey; 125 | } 126 | 127 | private function generate256(string $key) 128 | { 129 | list(, $k0, $k1, $k2, $k3, $k4, $k5, $k6, $k7) = unpack('N8', $key); 130 | 131 | $encryptionKey = [$k0, $k1, $k2, $k3, $k4, $k5, $k6, $k7]; 132 | $decryptionKey = [ 133 | $k0, $k1, $k2, $k3, 134 | $this->decryptionKeyRound($k4), 135 | $this->decryptionKeyRound($k5), 136 | $this->decryptionKeyRound($k6), 137 | $this->decryptionKeyRound($k7) 138 | ]; 139 | 140 | for ($i = 8, $rc = 1; $i < 56; $rc <<= 1) { 141 | $encryptionKey[$i ] = $k0 ^= $this->encryptionKeyRound($k7, $rc); 142 | $decryptionKey[$i++] = $this->decryptionKeyRound($k0); 143 | $encryptionKey[$i ] = $k1 ^= $k0; 144 | $decryptionKey[$i++] = $this->decryptionKeyRound($k1); 145 | $encryptionKey[$i ] = $k2 ^= $k1; 146 | $decryptionKey[$i++] = $this->decryptionKeyRound($k2); 147 | $encryptionKey[$i ] = $k3 ^= $k2; 148 | $decryptionKey[$i++] = $this->decryptionKeyRound($k3); 149 | $encryptionKey[$i ] = $k4 ^= (SUBBYTES[$k3 & 0xff] | (SUBBYTES[$k3 >> 8 & 0xff] << 8) | (SUBBYTES[$k3 >> 16 & 0xff] << 16) | (SUBBYTES[$k3 >> 24] << 24)); 150 | $decryptionKey[$i++] = $this->decryptionKeyRound($k4); 151 | $encryptionKey[$i ] = $k5 ^= $k4; 152 | $decryptionKey[$i++] = $this->decryptionKeyRound($k5); 153 | $encryptionKey[$i ] = $k6 ^= $k5; 154 | $decryptionKey[$i++] = $this->decryptionKeyRound($k6); 155 | $encryptionKey[$i ] = $k7 ^= $k6; 156 | $decryptionKey[$i++] = $this->decryptionKeyRound($k7); 157 | } 158 | 159 | $encryptionKey[56] = $decryptionKey[56] = $k0 ^= $this->encryptionKeyRound($k7, 0x40); 160 | $encryptionKey[57] = $decryptionKey[57] = $k1 ^= $k0; 161 | $encryptionKey[58] = $decryptionKey[58] = $k2 ^= $k1; 162 | $encryptionKey[59] = $decryptionKey[59] = $k3 ^ $k2; 163 | 164 | $this->encryptionKey = $encryptionKey; 165 | $this->decryptionKey = $decryptionKey; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /lib/OCB.php: -------------------------------------------------------------------------------- 1 | 1 && self::NONCEBYTES < 16); 27 | assert(self::TAGBYES > 1 && self::TAGBYES <= 16); 28 | 29 | if (strlen($nonce) !== self::NONCEBYTES) { 30 | throw new IVLengthException; 31 | } 32 | 33 | $context->key = $key; 34 | // Reference code defines L_* and L_$ 35 | $context->lstar = $this->encryptBlock($key, self::NULL_STR); 36 | $context->ldollar = $this->calc_L_i($context->lstar, 1); 37 | 38 | $nonce = str_pad("\1" . $nonce, 16, "\0", STR_PAD_LEFT); 39 | $nonce[0] = chr(((self::TAGBYES << 3) % 128) << 1); 40 | $bottom = ord($nonce[15]) & 0x3f; 41 | $nonce[15] = $nonce[15] & "\xc0"; 42 | 43 | $ktop = $this->encryptBlock($context->key, $nonce); 44 | list(, $stretch0, $stretch1, $stretch2) = unpack('J3', $ktop . (substr($ktop, 1, 8) ^ $ktop)); 45 | 46 | $bottomMask = ~(-1 << $bottom); 47 | $messageOffset = pack('J2', 48 | $stretch0 << $bottom | (($stretch1 >> (64 - $bottom)) & $bottomMask), 49 | $stretch1 << $bottom | (($stretch2 >> (64 - $bottom)) & $bottomMask) 50 | ); 51 | 52 | $context->cryptOffset = $messageOffset; 53 | } 54 | 55 | function initEncryption(Key $key, string $iv): EncryptionContext 56 | { 57 | $context = new EncryptionContext; 58 | $this->init($context, $key, $iv); 59 | return $context; 60 | } 61 | 62 | function initDecryption(Key $key, string $iv): DecryptionContext 63 | { 64 | $context = new DecryptionContext; 65 | $this->init($context, $key, $iv); 66 | return $context; 67 | } 68 | 69 | private function calc_L_i(string $ldollar, int $i): string 70 | { 71 | list(, $l0, $l1) = unpack('J2', $ldollar); 72 | 73 | do { 74 | $tmp = ($l0 >> 63 & 1); 75 | $l0 = $l0 << 1 | ($l1 >> 63 & 1); 76 | $l1 = $l1 << 1 ^ ($tmp * 135); 77 | } while (($i & 1) === 0 && $i >>= 1); 78 | 79 | return pack('J2', $l0, $l1); 80 | } 81 | 82 | function aad(Context $context, string $aad) 83 | { 84 | if ($context->finalised) { 85 | throw new InvalidContextException('Cannot process more data after finalise() has been called.'); 86 | } 87 | 88 | $aad = $context->aadBuffer . $aad; 89 | 90 | $aadOffset = $context->aadOffset; 91 | $aadSum = $context->aadSum; 92 | $blockIndex = $context->aadBlock; 93 | 94 | $blockOffset = 0; 95 | $blockCount = strlen($aad) >> 4; 96 | while ($blockCount--) { 97 | $aadBlock = substr($aad, $blockOffset, 16); 98 | $aadOffset ^= $this->calc_L_i($context->ldollar, ++$blockIndex); 99 | 100 | $aadSum ^= $this->encryptBlock($context->key, $aadOffset ^ $aadBlock); 101 | 102 | $blockOffset += 16; 103 | } 104 | 105 | $context->aadOffset = $aadOffset; 106 | $context->aadSum = $aadSum; 107 | $context->aadBlock = $blockIndex; 108 | $context->aadBuffer = substr($aad, $blockOffset); 109 | } 110 | 111 | function streamEncrypt(EncryptionContext $context, string $message): string 112 | { 113 | if ($context->finalised) { 114 | throw new InvalidContextException('Cannot process more data after finalise() has been called.'); 115 | } 116 | 117 | $message = $context->cryptBuffer . $message; 118 | 119 | $cryptOffset = $context->cryptOffset; 120 | $cryptSum = $context->cryptSum; 121 | $blockIndex = $context->cryptIndex; 122 | 123 | $ciphertext = ''; 124 | $messageOffset = 0; 125 | $blockCount = strlen($message) >> 4; 126 | while ($blockCount--) { 127 | $messageBlock = substr($message, $messageOffset, 16); 128 | $cryptOffset ^= $this->calc_L_i($context->ldollar, ++$blockIndex); 129 | 130 | $cryptSum ^= $messageBlock; 131 | $encryptedBlock = $cryptOffset ^ $this->encryptBlock($context->key, $cryptOffset ^ $messageBlock); 132 | $ciphertext .= $encryptedBlock; 133 | 134 | $messageOffset += 16; 135 | } 136 | 137 | $context->cryptOffset = $cryptOffset; 138 | $context->cryptSum = $cryptSum; 139 | $context->cryptIndex = $blockIndex; 140 | $context->cryptBuffer = substr($message, $messageOffset); 141 | 142 | return $ciphertext; 143 | } 144 | 145 | function streamDecrypt(DecryptionContext $context, string $message): string 146 | { 147 | if ($context->finalised) { 148 | throw new InvalidContextException('Cannot process more data after finalise() has been called.'); 149 | } 150 | 151 | $message = $context->cryptBuffer . $message; 152 | $cryptOffset = $context->cryptOffset; 153 | $cryptSum = $context->cryptSum; 154 | $blockIndex = $context->cryptIndex; 155 | 156 | $plaintext = ''; 157 | $messageOffset = 0; 158 | $blockCount = strlen($message) >> 4; 159 | while ($blockCount--) { 160 | $messageBlock = substr($message, $messageOffset, 16); 161 | $cryptOffset ^= $this->calc_L_i($context->ldollar, ++$blockIndex); 162 | 163 | $decryptedBlock = $cryptOffset ^ $this->decryptBlock($context->key, $cryptOffset ^ $messageBlock); 164 | $cryptSum ^= $decryptedBlock; 165 | $plaintext .= $decryptedBlock; 166 | 167 | $messageOffset += 16; 168 | } 169 | 170 | $context->cryptOffset = $cryptOffset; 171 | $context->cryptSum = $cryptSum; 172 | $context->cryptIndex = $blockIndex; 173 | $context->cryptBuffer = substr($message, $messageOffset); 174 | 175 | return $plaintext; 176 | } 177 | 178 | function encrypt(Key $key, string $iv, string $aad, string $message): array 179 | { 180 | $context = $this->initEncryption($key, $iv); 181 | $this->aad($context, $aad); 182 | 183 | return [ 184 | $this->streamEncrypt($context, $message) . $this->finalise($context), 185 | $this->tag($context) 186 | ]; 187 | } 188 | 189 | function decrypt(Key $key, string $iv, string $aad, string $message, string $tag): string 190 | { 191 | $context = $this->initDecryption($key, $iv); 192 | $this->aad($context, $aad); 193 | 194 | $plaintext = $this->streamDecrypt($context, $message) . $this->finalise($context); 195 | $this->verify($context, $tag); 196 | 197 | return $plaintext; 198 | } 199 | 200 | function finalise(Context $context): string 201 | { 202 | if ($context->finalised) { 203 | throw new InvalidContextException('Final block has already been processed'); 204 | } 205 | $context->finalised = true; 206 | 207 | $pad = ''; 208 | $message = $context->cryptBuffer; 209 | if (strlen($message) % 16) { 210 | $context->cryptOffset ^= $context->lstar; 211 | 212 | $pad = $message ^ $this->encryptBlock($context->key, $context->cryptOffset); 213 | 214 | if ($context instanceof EncryptionContext) { 215 | $context->cryptSum ^= $message . self::PAD_STR; 216 | } 217 | else { 218 | $context->cryptSum ^= $pad . self::PAD_STR; 219 | } 220 | } 221 | 222 | $aad = $context->aadBuffer; 223 | if (strlen($aad) % 16) { 224 | $context->aadSum ^= $this->encryptBlock($context->key, $context->aadOffset ^ $context->lstar ^ ($aad . self::PAD_STR)); 225 | } 226 | 227 | return $pad; 228 | } 229 | 230 | function tag(Context $ctx): string 231 | { 232 | $tag = $ctx->aadSum ^ $this->encryptBlock($ctx->key, $ctx->cryptSum ^ $ctx->cryptOffset ^ $ctx->ldollar); 233 | return substr($tag, 0, self::TAGBYES); 234 | } 235 | 236 | function verify(Context $ctx, string $tag) 237 | { 238 | if (!hash_equals($this->tag($ctx), $tag)) { 239 | throw new AuthenticationException; 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /lib/OFB.php: -------------------------------------------------------------------------------- 1 | key = $key; 21 | $context->iv = $iv; 22 | } 23 | 24 | function initEncryption(Key $key, string $iv): EncryptionContext 25 | { 26 | $context = new EncryptionContext; 27 | $this->init($context, $key, $iv); 28 | return $context; 29 | } 30 | 31 | function initDecryption(Key $key, string $iv): DecryptionContext 32 | { 33 | $context = new DecryptionContext; 34 | $this->init($context, $key, $iv); 35 | return $context; 36 | } 37 | 38 | private function transcrypt(Context $context, string $message): string 39 | { 40 | $iv = $context->iv; 41 | $keyStream = $context->keyStream; 42 | 43 | $bytesRequired = strlen($message) - strlen($keyStream); 44 | $bytesOver = $bytesRequired % 16; 45 | 46 | $blockCount = ($bytesRequired >> 4) + ($bytesOver > 0); 47 | while ($blockCount-- > 0) { 48 | $iv = $this->encryptBlock($context->key, $iv); 49 | $keyStream .= $iv; 50 | } 51 | 52 | $context->buffer = substr($keyStream, $bytesRequired); 53 | $context->iv = $iv; 54 | 55 | return $message ^ $keyStream; 56 | } 57 | 58 | function streamEncrypt(EncryptionContext $context, string $message): string 59 | { 60 | return $this->transcrypt($context, $message); 61 | } 62 | 63 | function streamDecrypt(DecryptionContext $context, string $message): string 64 | { 65 | return $this->transcrypt($context, $message); 66 | } 67 | 68 | function encrypt(Key $key, string $iv, string $message): string 69 | { 70 | $context = $this->initEncryption($key, $iv); 71 | return $this->streamEncrypt($context, $message); 72 | } 73 | 74 | function decrypt(Key $key, string $iv, string $message): string 75 | { 76 | $context = $this->initDecryption($key, $iv); 77 | return $this->streamDecrypt($context, $message); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/Padding/ANSIX923.php: -------------------------------------------------------------------------------- 1 | 16) { 24 | throw new InvalidPaddingException('Invalid padding'); 25 | } 26 | 27 | $i = $messageLen - 1; 28 | $limit = $messageLen - $padLen; 29 | while ($i > $limit) { 30 | if ($message[--$i] !== "\0") { 31 | throw new InvalidPaddingException('Invalid padding'); 32 | } 33 | } 34 | 35 | return $padLen; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/Padding/ISOIEC7816.php: -------------------------------------------------------------------------------- 1 | 16) { 25 | throw new InvalidPaddingException('Invalid padding'); 26 | } 27 | 28 | $i = $messageLen - 1; 29 | $limit = $messageLen - $padLen; 30 | while ($i > $limit) { 31 | if ($message[--$i] !== $padChar) { 32 | throw new InvalidPaddingException('Invalid padding'); 33 | } 34 | } 35 | 36 | return $padLen; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/Padding/Scheme.php: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | test 17 | 18 | 19 | 20 | 21 | lib 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/CBC/CBCGFSbox128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 38 | $this->assertSame(hex2bin($ciphertext), $result); 39 | } 40 | 41 | /** 42 | * @dataProvider caseProvider 43 | */ 44 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 45 | { 46 | $key = new Key(hex2bin($key)); 47 | $cbc = new CBC; 48 | $result = $cbc->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 49 | $this->assertSame(hex2bin($plaintext), $result); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/CBC/CBCGFSbox192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 37 | $this->assertSame(hex2bin($ciphertext), $result); 38 | } 39 | 40 | /** 41 | * @dataProvider caseProvider 42 | */ 43 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 44 | { 45 | $key = new Key(hex2bin($key)); 46 | $cbc = new CBC; 47 | $result = $cbc->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 48 | $this->assertSame(hex2bin($plaintext), $result); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/CBC/CBCGFSbox256Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 36 | $this->assertSame(hex2bin($ciphertext), $result); 37 | } 38 | 39 | /** 40 | * @dataProvider caseProvider 41 | */ 42 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 43 | { 44 | $key = new Key(hex2bin($key)); 45 | $cbc = new CBC; 46 | $result = $cbc->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 47 | $this->assertSame(hex2bin($plaintext), $result); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/CBC/CBCKeySbox128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 52 | $this->assertSame(hex2bin($ciphertext), $result); 53 | } 54 | 55 | /** 56 | * @dataProvider caseProvider 57 | */ 58 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 59 | { 60 | $key = new Key(hex2bin($key)); 61 | $cbc = new CBC; 62 | $result = $cbc->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 63 | $this->assertSame(hex2bin($plaintext), $result); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/CBC/CBCKeySbox192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 55 | $this->assertSame(hex2bin($ciphertext), $result); 56 | } 57 | 58 | /** 59 | * @dataProvider caseProvider 60 | */ 61 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 62 | { 63 | $key = new Key(hex2bin($key)); 64 | $cbc = new CBC; 65 | $result = $cbc->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 66 | $this->assertSame(hex2bin($plaintext), $result); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/CBC/CBCKeySbox256Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 47 | $this->assertSame(hex2bin($ciphertext), $result); 48 | } 49 | 50 | /** 51 | * @dataProvider caseProvider 52 | */ 53 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 54 | { 55 | $key = new Key(hex2bin($key)); 56 | $cbc = new CBC; 57 | $result = $cbc->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 58 | $this->assertSame(hex2bin($plaintext), $result); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/CBC/CBCMMT128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 57 | $this->assertSame(hex2bin($ciphertext), $result); 58 | } 59 | 60 | /** 61 | * @dataProvider decryptProvider 62 | */ 63 | function testDecrypt($key, $iv, $ciphertext, $plaintext) 64 | { 65 | $key = new Key(hex2bin($key)); 66 | $cbc = new CBC; 67 | $result = $cbc->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 68 | $this->assertSame(hex2bin($plaintext), $result); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/CBC/CBCMMT192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 57 | $this->assertSame(hex2bin($ciphertext), $result); 58 | } 59 | 60 | /** 61 | * @dataProvider decryptProvider 62 | */ 63 | function testDecrypt($key, $iv, $ciphertext, $plaintext) 64 | { 65 | $key = new Key(hex2bin($key)); 66 | $cbc = new CBC; 67 | $result = $cbc->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 68 | $this->assertSame(hex2bin($plaintext), $result); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/CFB/CFB128GFSbox128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 38 | $this->assertSame(hex2bin($ciphertext), $result); 39 | } 40 | 41 | /** 42 | * @dataProvider caseProvider 43 | */ 44 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 45 | { 46 | $key = new Key(hex2bin($key)); 47 | $cfb = new CFB; 48 | $result = $cfb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 49 | $this->assertSame(hex2bin($plaintext), $result); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/CFB/CFB128GFSbox192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 37 | $this->assertSame(hex2bin($ciphertext), $result); 38 | } 39 | 40 | /** 41 | * @dataProvider caseProvider 42 | */ 43 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 44 | { 45 | $key = new Key(hex2bin($key)); 46 | $cfb = new CFB; 47 | $result = $cfb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 48 | $this->assertSame(hex2bin($plaintext), $result); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/CFB/CFB128GFSbox256Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 36 | $this->assertSame(hex2bin($ciphertext), $result); 37 | } 38 | 39 | /** 40 | * @dataProvider caseProvider 41 | */ 42 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 43 | { 44 | $key = new Key(hex2bin($key)); 45 | $cfb = new CFB; 46 | $result = $cfb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 47 | $this->assertSame(hex2bin($plaintext), $result); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/CFB/CFB128KeySbox128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 52 | $this->assertSame(hex2bin($ciphertext), $result); 53 | } 54 | 55 | /** 56 | * @dataProvider caseProvider 57 | */ 58 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 59 | { 60 | $key = new Key(hex2bin($key)); 61 | $cfb = new CFB; 62 | $result = $cfb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 63 | $this->assertSame(hex2bin($plaintext), $result); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/CFB/CFB128KeySbox192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 55 | $this->assertSame(hex2bin($ciphertext), $result); 56 | } 57 | 58 | /** 59 | * @dataProvider caseProvider 60 | */ 61 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 62 | { 63 | $key = new Key(hex2bin($key)); 64 | $cfb = new CFB; 65 | $result = $cfb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 66 | $this->assertSame(hex2bin($plaintext), $result); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/CFB/CFB128KeySbox256Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 63 | $this->assertSame(hex2bin($ciphertext), $result); 64 | } 65 | 66 | /** 67 | * @dataProvider caseProvider 68 | */ 69 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 70 | { 71 | $key = new Key(hex2bin($key)); 72 | $cfb = new CFB; 73 | $result = $cfb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 74 | $this->assertSame(hex2bin($plaintext), $result); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /test/CFB/CFB128MMT128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 57 | $this->assertSame(hex2bin($ciphertext), $result); 58 | } 59 | 60 | /** 61 | * @dataProvider decryptProvider 62 | */ 63 | function testDecrypt($key, $iv, $ciphertext, $plaintext) 64 | { 65 | $key = new Key(hex2bin($key)); 66 | $cfb = new CFB; 67 | $result = $cfb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 68 | $this->assertSame(hex2bin($plaintext), $result); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/CTR/CTR128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), hex2bin('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710')); 20 | $this->assertSame(hex2bin('874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee'), $result); 21 | } 22 | 23 | function testDecrypt() 24 | { 25 | $key = new Key(hex2bin('2b7e151628aed2a6abf7158809cf4f3c')); 26 | $ctr = new CTR(); 27 | $result = $ctr->decrypt($key, hex2bin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), hex2bin('874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee')); 28 | $this->assertSame(hex2bin('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'), $result); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/CTR/CTR192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), hex2bin('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710')); 20 | $this->assertSame(hex2bin('1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e941e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050'), $result); 21 | } 22 | 23 | function testDecrypt() 24 | { 25 | $key = new Key(hex2bin('8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b')); 26 | $ctr = new CTR(); 27 | $result = $ctr->decrypt($key, hex2bin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), hex2bin('1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e941e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050')); 28 | $this->assertSame(hex2bin('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'), $result); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/CTR/CTR256Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), hex2bin('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710')); 20 | $this->assertSame(hex2bin('601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c52b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6'), $result); 21 | } 22 | 23 | function testDecrypt() 24 | { 25 | $key = new Key(hex2bin('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4')); 26 | $ctr = new CTR(); 27 | $result = $ctr->decrypt($key, hex2bin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'), hex2bin('601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c52b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6')); 28 | $this->assertSame(hex2bin('6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710'), $result); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/ECB/ECBGFSbox128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($plaintext)); 38 | $this->assertSame(hex2bin($ciphertext), $result); 39 | } 40 | 41 | /** 42 | * @dataProvider caseProvider 43 | */ 44 | function testDecrypt($key, $plaintext, $ciphertext) 45 | { 46 | $key = new Key(hex2bin($key)); 47 | $ecb = new ECB; 48 | $result = $ecb->decrypt($key, hex2bin($ciphertext)); 49 | $this->assertSame(hex2bin($plaintext), $result); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/ECB/ECBGFSbox192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($plaintext)); 37 | $this->assertSame(hex2bin($ciphertext), $result); 38 | } 39 | 40 | /** 41 | * @dataProvider caseProvider 42 | */ 43 | function testDecrypt($key, $plaintext, $ciphertext) 44 | { 45 | $key = new Key(hex2bin($key)); 46 | $ecb = new ECB; 47 | $result = $ecb->decrypt($key, hex2bin($ciphertext)); 48 | $this->assertSame(hex2bin($plaintext), $result); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/ECB/ECBGFSbox256Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($plaintext)); 36 | $this->assertSame(hex2bin($ciphertext), $result); 37 | } 38 | 39 | /** 40 | * @dataProvider caseProvider 41 | */ 42 | function testDecrypt($key, $plaintext, $ciphertext) 43 | { 44 | $key = new Key(hex2bin($key)); 45 | $ecb = new ECB; 46 | $result = $ecb->decrypt($key, hex2bin($ciphertext)); 47 | $this->assertSame(hex2bin($plaintext), $result); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/ECB/ECBKeySbox128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($plaintext)); 52 | $this->assertSame(hex2bin($ciphertext), $result); 53 | } 54 | 55 | /** 56 | * @dataProvider caseProvider 57 | */ 58 | function testDecrypt($key, $plaintext, $ciphertext) 59 | { 60 | $key = new Key(hex2bin($key)); 61 | $ecb = new ECB; 62 | $result = $ecb->decrypt($key, hex2bin($ciphertext)); 63 | $this->assertSame(hex2bin($plaintext), $result); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/ECB/ECBKeySbox192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($plaintext)); 55 | $this->assertSame(hex2bin($ciphertext), $result); 56 | } 57 | 58 | /** 59 | * @dataProvider caseProvider 60 | */ 61 | function testDecrypt($key, $plaintext, $ciphertext) 62 | { 63 | $key = new Key(hex2bin($key)); 64 | $ecb = new ECB; 65 | $result = $ecb->decrypt($key, hex2bin($ciphertext)); 66 | $this->assertSame(hex2bin($plaintext), $result); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/ECB/ECBKeySbox256Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($plaintext)); 47 | $this->assertSame(hex2bin($ciphertext), $result); 48 | } 49 | 50 | /** 51 | * @dataProvider caseProvider 52 | */ 53 | function testDecrypt($key, $plaintext, $ciphertext) 54 | { 55 | $key = new Key(hex2bin($key)); 56 | $ecb = new ECB; 57 | $result = $ecb->decrypt($key, hex2bin($ciphertext)); 58 | $this->assertSame(hex2bin($plaintext), $result); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/ECB/ECBMMT128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($plaintext)); 57 | $this->assertSame(hex2bin($ciphertext), $result); 58 | } 59 | 60 | /** 61 | * @dataProvider decryptProvider 62 | */ 63 | function testDecrypt($key, $ciphertext, $plaintext) 64 | { 65 | $key = new Key(hex2bin($key)); 66 | $ecb = new ECB; 67 | $result = $ecb->decrypt($key, hex2bin($ciphertext)); 68 | $this->assertSame(hex2bin($plaintext), $result); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/ECB/ECBMMT192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($plaintext)); 57 | $this->assertSame(hex2bin($ciphertext), $result); 58 | } 59 | 60 | /** 61 | * @dataProvider decryptProvider 62 | */ 63 | function testDecrypt($key, $ciphertext, $plaintext) 64 | { 65 | $key = new Key(hex2bin($key)); 66 | $ecb = new ECB; 67 | $result = $ecb->decrypt($key, hex2bin($ciphertext)); 68 | $this->assertSame(hex2bin($plaintext), $result); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/ECB/ECBMMT256Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($plaintext)); 57 | $this->assertSame(hex2bin($ciphertext), $result); 58 | } 59 | 60 | /** 61 | * @dataProvider decryptProvider 62 | */ 63 | function testDecrypt($key, $ciphertext, $plaintext) 64 | { 65 | $key = new Key(hex2bin($key)); 66 | $ecb = new ECB; 67 | $result = $ecb->decrypt($key, hex2bin($ciphertext)); 68 | $this->assertSame(hex2bin($plaintext), $result); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/OCB/OCBTest.php: -------------------------------------------------------------------------------- 1 | key)); 41 | $ocb = new OCB(); 42 | 43 | list($result, $resultTag) = $ocb->encrypt($key, hex2bin($iv), hex2bin($aad), hex2bin($plaintext)); 44 | 45 | $this->assertSame(hex2bin($ciphertext), $result); 46 | $this->assertSame(hex2bin($tag), $resultTag); 47 | } 48 | 49 | /** 50 | * @dataProvider caseProvider 51 | */ 52 | function testDecrypt($iv, $aad, $plaintext, $ciphertext, $tag) 53 | { 54 | $key = new Key(hex2bin($this->key)); 55 | $ocb = new OCB(); 56 | 57 | $result = $ocb->decrypt($key, hex2bin($iv), hex2bin($aad), hex2bin($ciphertext), hex2bin($tag)); 58 | 59 | $this->assertSame(hex2bin($plaintext), $result); 60 | } 61 | 62 | /** 63 | * @dataProvider caseProvider 64 | */ 65 | function testEncryptMultiMessage($iv, $aad, $plaintext, $ciphertext, $tag) 66 | { 67 | $key = new Key(hex2bin($this->key)); 68 | $ocb = new OCB(); 69 | 70 | $ctx = $ocb->initEncryption($key, hex2bin($iv)); 71 | 72 | $data = str_split(hex2bin($aad), 7); 73 | foreach ($data as $chunk) { 74 | $ocb->aad($ctx, $chunk); 75 | } 76 | 77 | $result = ''; 78 | $plain = str_split(hex2bin($plaintext), 7); 79 | foreach ($plain as $chunk) { 80 | $result .= $ocb->streamEncrypt($ctx, $chunk); 81 | } 82 | 83 | $result .= $ocb->finalise($ctx); 84 | $resultTag = $ocb->tag($ctx); 85 | 86 | $this->assertSame(hex2bin($ciphertext), $result); 87 | $this->assertSame(hex2bin($tag), $resultTag); 88 | } 89 | 90 | /** 91 | * @dataProvider caseProvider 92 | */ 93 | function testDecryptMultiMessage($nonce, $aad, $plaintext, $ciphertext, $tag) 94 | { 95 | $key = new Key(hex2bin($this->key)); 96 | $ocb = new OCB(); 97 | 98 | $ctx = $ocb->initDecryption($key, hex2bin($nonce)); 99 | 100 | $data = str_split(hex2bin($aad), 7); 101 | foreach ($data as $chunk) { 102 | $ocb->aad($ctx, $chunk); 103 | } 104 | 105 | $result = ''; 106 | $cipher = str_split(hex2bin($ciphertext), 7); 107 | foreach ($cipher as $chunk) { 108 | $result .= $ocb->streamDecrypt($ctx, $chunk); 109 | } 110 | 111 | $result .= $ocb->finalise($ctx); 112 | $resultTag = $ocb->tag($ctx); 113 | 114 | $this->assertSame(hex2bin($plaintext), $result); 115 | $this->assertSame(hex2bin($tag), $resultTag); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /test/OFB/OFBGFSbox128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 38 | $this->assertSame(hex2bin($ciphertext), $result); 39 | } 40 | 41 | /** 42 | * @dataProvider caseProvider 43 | */ 44 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 45 | { 46 | $key = new Key(hex2bin($key)); 47 | $ofb = new OFB; 48 | $result = $ofb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 49 | $this->assertSame(hex2bin($plaintext), $result); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/OFB/OFBGFSbox192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 37 | $this->assertSame(hex2bin($ciphertext), $result); 38 | } 39 | 40 | /** 41 | * @dataProvider caseProvider 42 | */ 43 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 44 | { 45 | $key = new Key(hex2bin($key)); 46 | $ofb = new OFB; 47 | $result = $ofb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 48 | $this->assertSame(hex2bin($plaintext), $result); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/OFB/OFBGFSbox256Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 36 | $this->assertSame(hex2bin($ciphertext), $result); 37 | } 38 | 39 | /** 40 | * @dataProvider caseProvider 41 | */ 42 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 43 | { 44 | $key = new Key(hex2bin($key)); 45 | $ofb = new OFB; 46 | $result = $ofb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 47 | $this->assertSame(hex2bin($plaintext), $result); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/OFB/OFBKeySbox128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 52 | $this->assertSame(hex2bin($ciphertext), $result); 53 | } 54 | 55 | /** 56 | * @dataProvider caseProvider 57 | */ 58 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 59 | { 60 | $key = new Key(hex2bin($key)); 61 | $ofb = new OFB; 62 | $result = $ofb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 63 | $this->assertSame(hex2bin($plaintext), $result); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/OFB/OFBKeySbox192Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 55 | $this->assertSame(hex2bin($ciphertext), $result); 56 | } 57 | 58 | /** 59 | * @dataProvider caseProvider 60 | */ 61 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 62 | { 63 | $key = new Key(hex2bin($key)); 64 | $ofb = new OFB; 65 | $result = $ofb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 66 | $this->assertSame(hex2bin($plaintext), $result); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /test/OFB/OFBKeySbox256Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 47 | $this->assertSame(hex2bin($ciphertext), $result); 48 | } 49 | 50 | /** 51 | * @dataProvider caseProvider 52 | */ 53 | function testDecrypt($key, $iv, $plaintext, $ciphertext) 54 | { 55 | $key = new Key(hex2bin($key)); 56 | $ofb = new OFB; 57 | $result = $ofb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 58 | $this->assertSame(hex2bin($plaintext), $result); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/OFB/OFBMMT128Test.php: -------------------------------------------------------------------------------- 1 | encrypt($key, hex2bin($iv), hex2bin($plaintext)); 57 | $this->assertSame(hex2bin($ciphertext), $result); 58 | } 59 | 60 | /** 61 | * @dataProvider decryptProvider 62 | */ 63 | function testDecrypt($key, $iv, $ciphertext, $plaintext) 64 | { 65 | $key = new Key(hex2bin($key)); 66 | $ofb = new OFB; 67 | $result = $ofb->decrypt($key, hex2bin($iv), hex2bin($ciphertext)); 68 | $this->assertSame(hex2bin($plaintext), $result); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/Padding/ANSIX923Test.php: -------------------------------------------------------------------------------- 1 | getPadding($message); 52 | $this->assertSame($expected, $result); 53 | } 54 | 55 | /** 56 | * @dataProvider goodPadProvider 57 | */ 58 | function testGetPadLen($message, $expected) 59 | { 60 | $scheme = new ANSIX923(); 61 | $result = $scheme->getPaddingLength($message . $expected); 62 | $this->assertSame(16 - (strlen($message) % 16), $result); 63 | } 64 | 65 | /** 66 | * @expectedException \AES\Exception\InvalidPaddingException 67 | * @dataProvider badPadProvider 68 | */ 69 | function testBadGetPadLen($message, $expected) 70 | { 71 | $scheme = new ANSIX923(); 72 | $scheme->getPaddingLength($message . $expected); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /test/Padding/ISOIEC7816Test.php: -------------------------------------------------------------------------------- 1 | getPadding($message); 49 | $this->assertSame($expected, $result); 50 | } 51 | 52 | /** 53 | * @dataProvider goodPadProvider 54 | */ 55 | function testGetPadLen($message, $expected) 56 | { 57 | $scheme = new ISOIEC7816(); 58 | $result = $scheme->getPaddingLength($message . $expected); 59 | $this->assertSame(16 - (strlen($message) % 16), $result); 60 | } 61 | 62 | /** 63 | * @expectedException \AES\Exception\InvalidPaddingException 64 | * @dataProvider badPadProvider 65 | */ 66 | function testBadGetPadLen($message, $expected) 67 | { 68 | $scheme = new ISOIEC7816(); 69 | $scheme->getPaddingLength($message . $expected); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /test/Padding/PKCS7Test.php: -------------------------------------------------------------------------------- 1 | getPadding($message); 50 | $this->assertSame($expected, $result); 51 | } 52 | 53 | /** 54 | * @dataProvider goodPadProvider 55 | */ 56 | function testGetPadLen($message, $expected) 57 | { 58 | $scheme = new PKCS7(); 59 | $result = $scheme->getPaddingLength($message . $expected); 60 | $this->assertSame(16 - (strlen($message) % 16), $result); 61 | } 62 | 63 | /** 64 | * @expectedException \AES\Exception\InvalidPaddingException 65 | * @dataProvider badPadProvider 66 | */ 67 | function testBadGetPadLen($message, $expected) 68 | { 69 | $scheme = new PKCS7(); 70 | $scheme->getPaddingLength($message . $expected); 71 | } 72 | } 73 | --------------------------------------------------------------------------------