diff --git a/BENCHMARK.md b/BENCHMARK.md
index 7509bf7..eb8f1a8 100644
--- a/BENCHMARK.md
+++ b/BENCHMARK.md
@@ -10,111 +10,120 @@ With 1MB message (10 iterations):
| Algorithms | `cipherlib` | `PointyCastle` | `cryptography` |
| ----------------- | ------------- | ----------------------------- | ---------------------------- |
-| XOR | **2.05 Gbps** | | |
-| ChaCha20 | **1.22 Gbps** | 276 Mbps
`4.41x slow` | |
-| ChaCha20/Poly1305 | **782 Mbps** | 201 Mbps
`3.88x slow` | 288 Mbps
`2.72x slow` |
-| Salsa20 | **1.22 Gbps** | 247 Mbps
`4.95x slow` | |
-| Salsa20/Poly1305 | **778 Mbps** | | |
-| AES-128:keygen | **138 Tbps** | 23.06 Tbps
`5.97x slow` | 56.09 Tbps
`2.45x slow` |
-| AES-192:keygen | **144 Tbps** | 19.97 Tbps
`7.21x slow` | 50.94 Tbps
`2.83x slow` |
-| AES-256:keygen | **110 Tbps** | 16.62 Tbps
`6.63x slow` | 43.68 Tbps
`2.52x slow` |
-| AES-128/ECB | **929 Mbps** | 172 Mbps
`5.41x slow` | |
-| AES-192/ECB | **839 Mbps** | 148 Mbps
`5.66x slow` | |
-| AES-256/ECB | **752 Mbps** | 133 Mbps
`5.65x slow` | |
-| AES-128/CBC | **909 Mbps** | 160 Mbps
`5.67x slow` | 817 Mbps
`1.11x slow` |
-| AES-192/CBC | **822 Mbps** | 140 Mbps
`5.85x slow` | 770 Mbps
`1.07x slow` |
-| AES-256/CBC | **754 Mbps** | 126 Mbps
`5.97x slow` | 710 Mbps
`1.06x slow` |
-| AES-128/CTR | **934 Mbps** | 158 Mbps
`5.91x slow` | 502 Mbps
`1.86x slow` |
-| AES-192/CTR | **847 Mbps** | 138 Mbps
`6.14x slow` | 474 Mbps
`1.79x slow` |
-| AES-256/CTR | **769 Mbps** | 123 Mbps
`6.24x slow` | 447 Mbps
`1.72x slow` |
-| AES-128/GCM | **144 Mbps** | 12 Mbps
`12.02x slow` | 134 Mbps
`1.08x slow` |
-| AES-192/GCM | **142 Mbps** | 11.91 Mbps
`11.91x slow` | 132 Mbps
`1.08x slow` |
-| AES-256/GCM | **139 Mbps** | 11.75 Mbps
`11.86x slow` | 130 Mbps
`1.07x slow` |
-| AES-128/CFB | **451 Mbps** | 781 kbps
`577.91x slow` | |
-| AES-192/CFB | **412 Mbps** | 783 kbps
`526.15x slow` | |
-| AES-256/CFB | **373 Mbps** | 780 kbps
`478.83x slow` | |
-| AES-128/OFB | **807 Mbps** | 163 Mbps
`4.95x slow` | |
-| AES-192/OFB | **739 Mbps** | 141 Mbps
`5.25x slow` | |
-| AES-256/OFB | **683 Mbps** | 126 Mbps
`5.42x slow` | |
-| AES-128/XTS | **676 Mbps** | | |
-| AES-192/XTS | **630 Mbps** | | |
-| AES-256/XTS | **584 Mbps** | | |
-| AES-128/PCBC | **854 Mbps** | | |
-| AES-192/PCBC | **775 Mbps** | | |
-| AES-256/PCBC | **711 Mbps** | | |
+| XOR | **5.74 Gbps** |
+| ChaCha20 | **1.21 Gbps** | 264 Mbps
`4.6x slow` | |
+| ChaCha20/Poly1305 | **765 Mbps** | 194 Mbps
`3.94x slow` | 289 Mbps
`2.65x slow` |
+| Salsa20 | **1.23 Gbps** | 253 Mbps
`4.85x slow` | |
+| Salsa20/Poly1305 | **771 Mbps** | | |
+| AES-128:keygen | **131 Tbps** | 22.48 Tbps
`5.82x slow` | 52.37 Tbps
`2.5x slow` |
+| AES-192:keygen | **136 Tbps** | 19.32 Tbps
`7.04x slow` | 47.34 Tbps
`2.87x slow` |
+| AES-256:keygen | **101 Tbps** | 16.24 Tbps
`6.24x slow` | 40.49 Tbps
`2.5x slow` |
+| AES-128/ECB | **944 Mbps** | 161 Mbps
`5.85x slow` | |
+| AES-192/ECB | **853 Mbps** | 145 Mbps
`5.88x slow` | |
+| AES-256/ECB | **776 Mbps** | 127 Mbps
`6.12x slow` | |
+| AES-128/CBC | **964 Mbps** | 157 Mbps
`6.14x slow` | 859 Mbps
`1.12x slow` |
+| AES-192/CBC | **872 Mbps** | 138 Mbps
`6.32x slow` | 783 Mbps
`1.11x slow` |
+| AES-256/CBC | **793 Mbps** | 123 Mbps
`6.46x slow` | 712 Mbps
`1.11x slow` |
+| AES-128/CTR | **944 Mbps** | 153 Mbps
`6.16x slow` | 497 Mbps
`1.9x slow` |
+| AES-192/CTR | **858 Mbps** | 136 Mbps
`6.28x slow` | 473 Mbps
`1.81x slow` |
+| AES-256/CTR | **781 Mbps** | 121 Mbps
`6.48x slow` | 449 Mbps
`1.74x slow` |
+| AES-128/GCM | **143 Mbps** | 11.98 Mbps
`11.9x slow` | 129 Mbps
`1.1x slow` |
+| AES-192/GCM | **141 Mbps** | 11.9 Mbps
`11.88x slow` | 129 Mbps
`1.09x slow` |
+| AES-256/GCM | **139 Mbps** | 11.75 Mbps
`11.86x slow` | 126 Mbps
`1.11x slow` |
+| AES-128/CFB | **453 Mbps** | 658 kbps
`688.39x slow` | |
+| AES-192/CFB | **416 Mbps** | 661 kbps
`629.53x slow` | |
+| AES-256/CFB | **378 Mbps** | 659 kbps
`573.25x slow` | |
+| AES-128/OFB | **807 Mbps** | 155 Mbps
`5.19x slow` | |
+| AES-192/OFB | **744 Mbps** | 139 Mbps
`5.34x slow` | |
+| AES-256/OFB | **678 Mbps** | 124 Mbps
`5.47x slow` | |
+| AES-128/XTS | **667 Mbps** | | |
+| AES-192/XTS | **618 Mbps** | | |
+| AES-256/XTS | **578 Mbps** | | |
+| AES-128/IGE | **836 Mbps** | 150 Mbps
`5.56x slow` | |
+| AES-192/IGE | **762 Mbps** | 131 Mbps
`5.8x slow` | |
+| AES-256/IGE | **698 Mbps** | 117 Mbps
`5.96x slow` | |
+| AES-128/PCBC | **835 Mbps** | | |
+| AES-192/PCBC | **774 Mbps** | | |
+| AES-256/PCBC | **700 Mbps** | | |
With 5KB message (5000 iterations):
| Algorithms | `cipherlib` | `PointyCastle` | `cryptography` |
| ----------------- | ------------- | ----------------------------- | -------------------------- |
-| XOR | **2.15 Gbps** | | |
-| ChaCha20 | **1.25 Gbps** | 278 Mbps
`4.5x slow` | |
-| ChaCha20/Poly1305 | **783 Mbps** | 199 Mbps
`3.93x slow` | 281 Mbps
`2.78x slow` |
-| Salsa20 | **1.25 Gbps** | 252 Mbps
`4.96x slow` | |
-| Salsa20/Poly1305 | **784 Mbps** | | |
-| AES-128:keygen | **712 Gbps** | 117 Gbps
`6.09x slow` | 282 Gbps
`2.53x slow` |
-| AES-192:keygen | **748 Gbps** | 100 Gbps
`7.47x slow` | 255 Gbps
`2.94x slow` |
-| AES-256:keygen | **564 Gbps** | 83.55 Gbps
`6.75x slow` | 219 Gbps
`2.58x slow` |
-| AES-128/ECB | **938 Mbps** | 174 Mbps
`5.4x slow` | |
-| AES-192/ECB | **850 Mbps** | 151 Mbps
`5.64x slow` | |
-| AES-256/ECB | **772 Mbps** | 133 Mbps
`5.78x slow` | |
-| AES-128/CBC | **933 Mbps** | 162 Mbps
`5.74x slow` | 860 Mbps
`1.08x slow` |
-| AES-192/CBC | **840 Mbps** | 142 Mbps
`5.9x slow` | 778 Mbps
`1.08x slow` |
-| AES-256/CBC | **762 Mbps** | 126 Mbps
`6.02x slow` | 709 Mbps
`1.07x slow` |
-| AES-128/CTR | **957 Mbps** | 159 Mbps
`6.03x slow` | 506 Mbps
`1.89x slow` |
-| AES-192/CTR | **863 Mbps** | 139 Mbps
`6.2x slow` | 479 Mbps
`1.8x slow` |
-| AES-256/CTR | **781 Mbps** | 124 Mbps
`6.28x slow` | 453 Mbps
`1.72x slow` |
-| AES-128/GCM | **146 Mbps** | 11.87 Mbps
`12.29x slow` | 138 Mbps
`1.06x slow` |
-| AES-192/GCM | **144 Mbps** | 11.84 Mbps
`12.16x slow` | 135 Mbps
`1.07x slow` |
-| AES-256/GCM | **141 Mbps** | 11.67 Mbps
`12.08x slow` | 132 Mbps
`1.07x slow` |
-| AES-128/CFB | **458 Mbps** | 142 Mbps
`3.23x slow` | |
-| AES-192/CFB | **415 Mbps** | 126 Mbps
`3.29x slow` | |
-| AES-256/CFB | **380 Mbps** | 114 Mbps
`3.35x slow` | |
-| AES-128/OFB | **824 Mbps** | 164 Mbps
`5.01x slow` | |
-| AES-192/OFB | **748 Mbps** | 144 Mbps
`5.2x slow` | |
-| AES-256/OFB | **690 Mbps** | 127 Mbps
`5.45x slow` | |
-| AES-128/XTS | **698 Mbps** | | |
-| AES-192/XTS | **644 Mbps** | | |
-| AES-256/XTS | **601 Mbps** | | |
-| AES-128/PCBC | **852 Mbps** | | |
-| AES-192/PCBC | **777 Mbps** | | |
-| AES-256/PCBC | **702 Mbps** | | |
+| XOR | **6.74 Gbps** |
+| ChaCha20 | **1.26 Gbps** | 277 Mbps
`4.55x slow` | |
+| ChaCha20/Poly1305 | **765 Mbps** | 198 Mbps
`3.87x slow` | 280 Mbps
`2.73x slow` |
+| Salsa20 | **1.25 Gbps** | 254 Mbps
`4.9x slow` | |
+| Salsa20/Poly1305 | **761 Mbps** | | |
+| AES-128:keygen | **690 Gbps** | 109 Gbps
`6.35x slow` | 268 Gbps
`2.57x slow` |
+| AES-192:keygen | **708 Gbps** | 98.75 Gbps
`7.17x slow` | 242 Gbps
`2.92x slow` |
+| AES-256:keygen | **540 Gbps** | 83.27 Gbps
`6.48x slow` | 208 Gbps
`2.59x slow` |
+| AES-128/ECB | **953 Mbps** | 165 Mbps
`5.77x slow` | |
+| AES-192/ECB | **866 Mbps** | 144 Mbps
`6.01x slow` | |
+| AES-256/ECB | **790 Mbps** | 128 Mbps
`6.18x slow` | |
+| AES-128/CBC | **973 Mbps** | 158 Mbps
`6.15x slow` | 854 Mbps
`1.14x slow` |
+| AES-192/CBC | **879 Mbps** | 138 Mbps
`6.35x slow` | 774 Mbps
`1.14x slow` |
+| AES-256/CBC | **798 Mbps** | 123 Mbps
`6.49x slow` | 708 Mbps
`1.13x slow` |
+| AES-128/CTR | **950 Mbps** | 156 Mbps
`6.1x slow` | 503 Mbps
`1.89x slow` |
+| AES-192/CTR | **866 Mbps** | 138 Mbps
`6.3x slow` | 475 Mbps
`1.82x slow` |
+| AES-256/CTR | **780 Mbps** | 122 Mbps
`6.39x slow` | 450 Mbps
`1.73x slow` |
+| AES-128/GCM | **145 Mbps** | 11.72 Mbps
`12.34x slow` | 131 Mbps
`1.11x slow` |
+| AES-192/GCM | **144 Mbps** | 11.7 Mbps
`12.3x slow` | 128 Mbps
`1.12x slow` |
+| AES-256/GCM | **141 Mbps** | 11.59 Mbps
`12.12x slow` | 128 Mbps
`1.1x slow` |
+| AES-128/CFB | **453 Mbps** | 136 Mbps
`3.32x slow` | |
+| AES-192/CFB | **419 Mbps** | 121 Mbps
`3.47x slow` | |
+| AES-256/CFB | **381 Mbps** | 108 Mbps
`3.54x slow` | |
+| AES-128/OFB | **760 Mbps** | 158 Mbps
`4.8x slow` | |
+| AES-192/OFB | **747 Mbps** | 139 Mbps
`5.39x slow` | |
+| AES-256/OFB | **689 Mbps** | 123 Mbps
`5.61x slow` | |
+| AES-128/XTS | **688 Mbps** | | |
+| AES-192/XTS | **634 Mbps** | | |
+| AES-256/XTS | **595 Mbps** | | |
+| AES-128/IGE | **843 Mbps** | 151 Mbps
`5.59x slow` | |
+| AES-192/IGE | **770 Mbps** | 133 Mbps
`5.77x slow` | |
+| AES-256/IGE | **710 Mbps** | 119 Mbps
`5.96x slow` | |
+| AES-128/PCBC | **843 Mbps** | | |
+| AES-192/PCBC | **778 Mbps** | | |
+| AES-256/PCBC | **690 Mbps** | | |
With 16B message (100000 iterations):
-| Algorithms | `cipherlib` | `PointyCastle` | `cryptography` |
-| ----------------- | ------------- | ---------------------------- | -------------------------------- |
-| XOR | **1.8 Gbps** | | |
-| ChaCha20 | **427 Mbps** | 51.3 Mbps
`8.33x slow` | |
-| ChaCha20/Poly1305 | **110 Mbps** | 44.61 Mbps
`2.46x slow` | 35.42 Mbps
`3.1x slow` |
-| Salsa20 | **410 Mbps** | 49.12 Mbps
`8.36x slow` | |
-| Salsa20/Poly1305 | **106 Mbps** | | |
-| AES-128:keygen | **2.17 Gbps** | 359 Mbps
`6.04x slow` | 850 Mbps
`2.55x slow` |
-| AES-192:keygen | **2.28 Gbps** | 307 Mbps
`7.44x slow` | 782 Mbps
`2.92x slow` |
-| AES-256:keygen | **1.75 Gbps** | 258 Mbps
`6.79x slow` | 675 Mbps
`2.59x slow` |
-| AES-128/ECB | **335 Mbps** | 54.15 Mbps
`6.18x slow` | |
-| AES-192/ECB | **322 Mbps** | 50.27 Mbps
`6.4x slow` | |
-| AES-256/ECB | **279 Mbps** | 46.33 Mbps
`6.01x slow` | |
-| AES-128/CBC | **301 Mbps** | 50.75 Mbps
`5.93x slow` | 149 Mbps
`2.03x slow` |
-| AES-192/CBC | **289 Mbps** | 47.15 Mbps
`6.14x slow` | 139 Mbps
`2.08x slow` |
-| AES-256/CBC | **259 Mbps** | 43.69 Mbps
`5.92x slow` | 130 Mbps
`1.99x slow` |
-| AES-128/CTR | **498 Mbps** | 51.14 Mbps
`9.75x slow` | 81.76 Mbps
`6.1x slow` |
-| AES-192/CTR | **485 Mbps** | 47.56 Mbps
`10.2x slow` | 79.22 Mbps
`6.12x slow` |
-| AES-256/CTR | **427 Mbps** | 44.38 Mbps
`9.62x slow` | 76.79 Mbps
`5.56x slow` |
-| AES-128/GCM | 27.28 Mbps | 6.53 Mbps
`4.18x slow` | **42.59 Mbps**
`1.56x fast` |
-| AES-192/GCM | 27.29 Mbps | 6.42 Mbps
`4.25x slow` | **41.49 Mbps**
`1.52x fast` |
-| AES-256/GCM | 26.57 Mbps | 6.29 Mbps
`4.23x slow` | **40.03 Mbps**
`1.51x fast` |
-| AES-128/CFB | **314 Mbps** | 50.7 Mbps
`6.2x slow` | |
-| AES-192/CFB | **292 Mbps** | 47.38 Mbps
`6.17x slow` | |
-| AES-256/CFB | **259 Mbps** | 44.34 Mbps
`5.83x slow` | |
-| AES-128/OFB | **446 Mbps** | 50.96 Mbps
`8.76x slow` | |
-| AES-192/OFB | **428 Mbps** | 47.28 Mbps
`9.06x slow` | |
-| AES-256/OFB | **382 Mbps** | 44.23 Mbps
`8.64x slow` | |
-| AES-128/XTS | **238 Mbps** | | |
-| AES-192/XTS | **227 Mbps** | | |
-| AES-256/XTS | **201 Mbps** | | |
-| AES-128/PCBC | **292 Mbps** | | |
-| AES-192/PCBC | **293 Mbps** | | |
-| AES-256/PCBC | **251 Mbps** | | |
+| Algorithms | `cipherlib` | `PointyCastle` | `cryptography` |
+| ----------------- | ------------- | ----------------------------- | -------------------------------- |
+| XOR | **4.65 Gbps** |
+| ChaCha20 | **420 Mbps** | 50.69 Mbps
`8.29x slow` | |
+| ChaCha20/Poly1305 | **110 Mbps** | 41.08 Mbps
`2.68x slow` | 34.87 Mbps
`3.15x slow` |
+| Salsa20 | **410 Mbps** | 48.25 Mbps
`8.51x slow` | |
+| Salsa20/Poly1305 | **110 Mbps** | | |
+| AES-128:keygen | **2.17 Gbps** | 360 Mbps
`6.03x slow` | 840 Mbps
`2.59x slow` |
+| AES-192:keygen | **2.28 Gbps** | 310 Mbps
`7.36x slow` | 759 Mbps
`3.01x slow` |
+| AES-256:keygen | **1.58 Gbps** | 259 Mbps
`6.11x slow` | 650 Mbps
`2.44x slow` |
+| AES-128/ECB | **358 Mbps** | 54.07 Mbps
`6.61x slow` | |
+| AES-192/ECB | **313 Mbps** | 49.44 Mbps
`6.33x slow` | |
+| AES-256/ECB | **280 Mbps** | 45.83 Mbps
`6.12x slow` | |
+| AES-128/CBC | **312 Mbps** | 50.29 Mbps
`6.2x slow` | 146 Mbps
`2.13x slow` |
+| AES-192/CBC | **286 Mbps** | 47.28 Mbps
`6.04x slow` | 142 Mbps
`2.02x slow` |
+| AES-256/CBC | **254 Mbps** | 44.26 Mbps
`5.74x slow` | 132 Mbps
`1.92x slow` |
+| AES-128/CTR | **493 Mbps** | 50.47 Mbps
`9.78x slow` | 80.75 Mbps
`6.11x slow` |
+| AES-192/CTR | **480 Mbps** | 46.99 Mbps
`10.22x slow` | 78.85 Mbps
`6.09x slow` |
+| AES-256/CTR | **425 Mbps** | 43.79 Mbps
`9.7x slow` | 76 Mbps
`5.59x slow` |
+| AES-128/GCM | 27.19 Mbps | 6.44 Mbps
`4.22x slow` | **41.33 Mbps**
`1.52x fast` |
+| AES-192/GCM | 27.06 Mbps | 6.38 Mbps
`4.24x slow` | **40.41 Mbps**
`1.49x fast` |
+| AES-256/GCM | 26.68 Mbps | 6.27 Mbps
`4.26x slow` | **39.05 Mbps**
`1.46x fast` |
+| AES-128/CFB | **307 Mbps** | 50.4 Mbps
`6.1x slow` | |
+| AES-192/CFB | **288 Mbps** | 46.91 Mbps
`6.13x slow` | |
+| AES-256/CFB | **254 Mbps** | 43.66 Mbps
`5.81x slow` | |
+| AES-128/OFB | **433 Mbps** | 51.04 Mbps
`8.48x slow` | |
+| AES-192/OFB | **423 Mbps** | 47.07 Mbps
`8.99x slow` | |
+| AES-256/OFB | **364 Mbps** | 44.54 Mbps
`8.18x slow` | |
+| AES-128/XTS | **229 Mbps** | | |
+| AES-192/XTS | **224 Mbps** | | |
+| AES-256/XTS | **196 Mbps** | | |
+| AES-128/IGE | **275 Mbps** | 49.15 Mbps
`5.6x slow` | |
+| AES-192/IGE | **270 Mbps** | 45.42 Mbps
`5.94x slow` | |
+| AES-256/IGE | **238 Mbps** | 42.69 Mbps
`5.58x slow` | |
+| AES-128/PCBC | **303 Mbps** | | |
+| AES-192/PCBC | **288 Mbps** | | |
+| AES-256/PCBC | **248 Mbps** | | |
> > Dart SDK version: 3.3.3 (stable) (Tue Mar 26 14:21:33 2024 +0000) on "windows_x64"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 11d7ba6..bb34b8d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
-## 0.0.10
+## 0.0.11
- `XOR` cipher.
- `Salsa20` cipher with `Poly1305` tag.
- `ChaCha20` cipher with `Poly1305` tag.
-- `AES` in ECB, CBC, CTR, CFB, OFB, GCM, XTS, PCBC modes.
+- `AES` in ECB, CBC, CTR, CFB, OFB, GCM, XTS, IGE, PCBC modes.
diff --git a/README.md b/README.md
index afeef5f..4fbb724 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,7 @@ Available modes for AES:
- `GCM` : Galois/Counter Mode
- `CFB` : Cipher Feedback
- `OFB` : Output Feedback
+- `IGE` : Infinite Garble Extension
- `PCBC` : Propagating Cipher Block Chaining
- `XTS` : XEX (XOR-Encrypt-XOR) Tweakable Block Cipher with Ciphertext Stealing
@@ -71,6 +72,7 @@ void main() {
print(' CFB: ${toHex(AES(key).cfb(iv).encryptString(plain))}');
print(' OFB: ${toHex(AES(key).ofb(iv).encryptString(plain))}');
print(' XTS: ${toHex(AES(key).xts(iv).encryptString(plain))}');
+ print(' IGE: ${toHex(AES(key).ige(iv).encryptString(plain))}');
print(' PCBC: ${toHex(AES(key).pcbc(iv).encryptString(plain))}');
}
print('');
@@ -131,41 +133,125 @@ Libraries:
- **PointyCastle** : https://pub.dev/packages/pointycastle
- **Cryptography** : https://pub.dev/packages/cryptography
-With 5MB message (10 iterations):
-
-| Algorithms | `cipherlib` | `PointyCastle` | `cryptography` |
-| ------------------------- | -------------- | ---------------------------- | ---------------------------- |
-| XOR | **241MB/s** | ➖ | ➖ |
-| ChaCha20 | **107.60MB/s** | 30.48MB/s
`253% slower` | ➖ |
-| ChaCha20/Poly1305 | **75.32MB/s** | ➖ | 33.24MB/s
`127% slower` |
-| ChaCha20/Poly1305(digest) | **247.47MB/s** | ➖ | ➖ |
-| Salsa20 | **107.24MB/s** | 27.91MB/s
`284% slower` | ➖ |
-| Salsa20/Poly1305 | **76.42MB/s** | ➖ | ➖ |
-| Salsa20/Poly1305(digest) | **248.50MB/s** | ➖ | ➖ |
-
-With 1KB message (5000 iterations):
-
-| Algorithms | `cipherlib` | `PointyCastle` | `cryptography` |
-| ------------------------- | -------------- | ---------------------------- | ---------------------------- |
-| XOR | **250.20MB/s** | ➖ | ➖ |
-| ChaCha20 | **108.38MB/s** | 30.87MB/s
`251% slower` | ➖ |
-| ChaCha20/Poly1305 | **71.48MB/s** | ➖ | 31.39MB/s
`128% slower` |
-| ChaCha20/Poly1305(digest) | **213.58MB/s** | ➖ | ➖ |
-| Salsa20 | **108.21MB/s** | 29.29MB/s
`269% slower` | ➖ |
-| Salsa20/Poly1305 | **72.17MB/s** | ➖ | ➖ |
-| Salsa20/Poly1305(digest) | **217.38MB/s** | ➖ | ➖ |
-
-With 10B message (100000 iterations):
-
-| Algorithms | `cipherlib` | `PointyCastle` | `cryptography` |
-| ------------------------- | -------------- | --------------------------- | --------------------------- |
-| XOR | **185.62MB/s** | ➖ | ➖ |
-| ChaCha20 | **32.03MB/s** | 3.91MB/s
`719% slower` | ➖ |
-| ChaCha20/Poly1305 | **9.71MB/s** | ➖ | 4.14MB/s
`134% slower` |
-| ChaCha20/Poly1305(digest) | **14.31MB/s** | ➖ | ➖ |
-| Salsa20 | **32.33MB/s** | 3.81MB/s
`748% slower` | ➖ |
-| Salsa20/Poly1305 | **9.81MB/s** | ➖ | ➖ |
-| Salsa20/Poly1305(digest) | **14.25MB/s** | ➖ | ➖ |
+With 1MB message (10 iterations):
+
+| Algorithms | `cipherlib` | `PointyCastle` | `cryptography` |
+| ----------------- | ------------- | ----------------------------- | ---------------------------- |
+| XOR | **5.74 Gbps** |
+| ChaCha20 | **1.21 Gbps** | 264 Mbps
`4.6x slow` | |
+| ChaCha20/Poly1305 | **765 Mbps** | 194 Mbps
`3.94x slow` | 289 Mbps
`2.65x slow` |
+| Salsa20 | **1.23 Gbps** | 253 Mbps
`4.85x slow` | |
+| Salsa20/Poly1305 | **771 Mbps** | | |
+| AES-128:keygen | **131 Tbps** | 22.48 Tbps
`5.82x slow` | 52.37 Tbps
`2.5x slow` |
+| AES-192:keygen | **136 Tbps** | 19.32 Tbps
`7.04x slow` | 47.34 Tbps
`2.87x slow` |
+| AES-256:keygen | **101 Tbps** | 16.24 Tbps
`6.24x slow` | 40.49 Tbps
`2.5x slow` |
+| AES-128/ECB | **944 Mbps** | 161 Mbps
`5.85x slow` | |
+| AES-192/ECB | **853 Mbps** | 145 Mbps
`5.88x slow` | |
+| AES-256/ECB | **776 Mbps** | 127 Mbps
`6.12x slow` | |
+| AES-128/CBC | **964 Mbps** | 157 Mbps
`6.14x slow` | 859 Mbps
`1.12x slow` |
+| AES-192/CBC | **872 Mbps** | 138 Mbps
`6.32x slow` | 783 Mbps
`1.11x slow` |
+| AES-256/CBC | **793 Mbps** | 123 Mbps
`6.46x slow` | 712 Mbps
`1.11x slow` |
+| AES-128/CTR | **944 Mbps** | 153 Mbps
`6.16x slow` | 497 Mbps
`1.9x slow` |
+| AES-192/CTR | **858 Mbps** | 136 Mbps
`6.28x slow` | 473 Mbps
`1.81x slow` |
+| AES-256/CTR | **781 Mbps** | 121 Mbps
`6.48x slow` | 449 Mbps
`1.74x slow` |
+| AES-128/GCM | **143 Mbps** | 11.98 Mbps
`11.9x slow` | 129 Mbps
`1.1x slow` |
+| AES-192/GCM | **141 Mbps** | 11.9 Mbps
`11.88x slow` | 129 Mbps
`1.09x slow` |
+| AES-256/GCM | **139 Mbps** | 11.75 Mbps
`11.86x slow` | 126 Mbps
`1.11x slow` |
+| AES-128/CFB | **453 Mbps** | 658 kbps
`688.39x slow` | |
+| AES-192/CFB | **416 Mbps** | 661 kbps
`629.53x slow` | |
+| AES-256/CFB | **378 Mbps** | 659 kbps
`573.25x slow` | |
+| AES-128/OFB | **807 Mbps** | 155 Mbps
`5.19x slow` | |
+| AES-192/OFB | **744 Mbps** | 139 Mbps
`5.34x slow` | |
+| AES-256/OFB | **678 Mbps** | 124 Mbps
`5.47x slow` | |
+| AES-128/XTS | **667 Mbps** | | |
+| AES-192/XTS | **618 Mbps** | | |
+| AES-256/XTS | **578 Mbps** | | |
+| AES-128/IGE | **836 Mbps** | 150 Mbps
`5.56x slow` | |
+| AES-192/IGE | **762 Mbps** | 131 Mbps
`5.8x slow` | |
+| AES-256/IGE | **698 Mbps** | 117 Mbps
`5.96x slow` | |
+| AES-128/PCBC | **835 Mbps** | | |
+| AES-192/PCBC | **774 Mbps** | | |
+| AES-256/PCBC | **700 Mbps** | | |
+
+With 5KB message (5000 iterations):
+
+| Algorithms | `cipherlib` | `PointyCastle` | `cryptography` |
+| ----------------- | ------------- | ----------------------------- | -------------------------- |
+| XOR | **6.74 Gbps** |
+| ChaCha20 | **1.26 Gbps** | 277 Mbps
`4.55x slow` | |
+| ChaCha20/Poly1305 | **765 Mbps** | 198 Mbps
`3.87x slow` | 280 Mbps
`2.73x slow` |
+| Salsa20 | **1.25 Gbps** | 254 Mbps
`4.9x slow` | |
+| Salsa20/Poly1305 | **761 Mbps** | | |
+| AES-128:keygen | **690 Gbps** | 109 Gbps
`6.35x slow` | 268 Gbps
`2.57x slow` |
+| AES-192:keygen | **708 Gbps** | 98.75 Gbps
`7.17x slow` | 242 Gbps
`2.92x slow` |
+| AES-256:keygen | **540 Gbps** | 83.27 Gbps
`6.48x slow` | 208 Gbps
`2.59x slow` |
+| AES-128/ECB | **953 Mbps** | 165 Mbps
`5.77x slow` | |
+| AES-192/ECB | **866 Mbps** | 144 Mbps
`6.01x slow` | |
+| AES-256/ECB | **790 Mbps** | 128 Mbps
`6.18x slow` | |
+| AES-128/CBC | **973 Mbps** | 158 Mbps
`6.15x slow` | 854 Mbps
`1.14x slow` |
+| AES-192/CBC | **879 Mbps** | 138 Mbps
`6.35x slow` | 774 Mbps
`1.14x slow` |
+| AES-256/CBC | **798 Mbps** | 123 Mbps
`6.49x slow` | 708 Mbps
`1.13x slow` |
+| AES-128/CTR | **950 Mbps** | 156 Mbps
`6.1x slow` | 503 Mbps
`1.89x slow` |
+| AES-192/CTR | **866 Mbps** | 138 Mbps
`6.3x slow` | 475 Mbps
`1.82x slow` |
+| AES-256/CTR | **780 Mbps** | 122 Mbps
`6.39x slow` | 450 Mbps
`1.73x slow` |
+| AES-128/GCM | **145 Mbps** | 11.72 Mbps
`12.34x slow` | 131 Mbps
`1.11x slow` |
+| AES-192/GCM | **144 Mbps** | 11.7 Mbps
`12.3x slow` | 128 Mbps
`1.12x slow` |
+| AES-256/GCM | **141 Mbps** | 11.59 Mbps
`12.12x slow` | 128 Mbps
`1.1x slow` |
+| AES-128/CFB | **453 Mbps** | 136 Mbps
`3.32x slow` | |
+| AES-192/CFB | **419 Mbps** | 121 Mbps
`3.47x slow` | |
+| AES-256/CFB | **381 Mbps** | 108 Mbps
`3.54x slow` | |
+| AES-128/OFB | **760 Mbps** | 158 Mbps
`4.8x slow` | |
+| AES-192/OFB | **747 Mbps** | 139 Mbps
`5.39x slow` | |
+| AES-256/OFB | **689 Mbps** | 123 Mbps
`5.61x slow` | |
+| AES-128/XTS | **688 Mbps** | | |
+| AES-192/XTS | **634 Mbps** | | |
+| AES-256/XTS | **595 Mbps** | | |
+| AES-128/IGE | **843 Mbps** | 151 Mbps
`5.59x slow` | |
+| AES-192/IGE | **770 Mbps** | 133 Mbps
`5.77x slow` | |
+| AES-256/IGE | **710 Mbps** | 119 Mbps
`5.96x slow` | |
+| AES-128/PCBC | **843 Mbps** | | |
+| AES-192/PCBC | **778 Mbps** | | |
+| AES-256/PCBC | **690 Mbps** | | |
+
+With 16B message (100000 iterations):
+
+| Algorithms | `cipherlib` | `PointyCastle` | `cryptography` |
+| ----------------- | ------------- | ----------------------------- | -------------------------------- |
+| XOR | **4.65 Gbps** |
+| ChaCha20 | **420 Mbps** | 50.69 Mbps
`8.29x slow` | |
+| ChaCha20/Poly1305 | **110 Mbps** | 41.08 Mbps
`2.68x slow` | 34.87 Mbps
`3.15x slow` |
+| Salsa20 | **410 Mbps** | 48.25 Mbps
`8.51x slow` | |
+| Salsa20/Poly1305 | **110 Mbps** | | |
+| AES-128:keygen | **2.17 Gbps** | 360 Mbps
`6.03x slow` | 840 Mbps
`2.59x slow` |
+| AES-192:keygen | **2.28 Gbps** | 310 Mbps
`7.36x slow` | 759 Mbps
`3.01x slow` |
+| AES-256:keygen | **1.58 Gbps** | 259 Mbps
`6.11x slow` | 650 Mbps
`2.44x slow` |
+| AES-128/ECB | **358 Mbps** | 54.07 Mbps
`6.61x slow` | |
+| AES-192/ECB | **313 Mbps** | 49.44 Mbps
`6.33x slow` | |
+| AES-256/ECB | **280 Mbps** | 45.83 Mbps
`6.12x slow` | |
+| AES-128/CBC | **312 Mbps** | 50.29 Mbps
`6.2x slow` | 146 Mbps
`2.13x slow` |
+| AES-192/CBC | **286 Mbps** | 47.28 Mbps
`6.04x slow` | 142 Mbps
`2.02x slow` |
+| AES-256/CBC | **254 Mbps** | 44.26 Mbps
`5.74x slow` | 132 Mbps
`1.92x slow` |
+| AES-128/CTR | **493 Mbps** | 50.47 Mbps
`9.78x slow` | 80.75 Mbps
`6.11x slow` |
+| AES-192/CTR | **480 Mbps** | 46.99 Mbps
`10.22x slow` | 78.85 Mbps
`6.09x slow` |
+| AES-256/CTR | **425 Mbps** | 43.79 Mbps
`9.7x slow` | 76 Mbps
`5.59x slow` |
+| AES-128/GCM | 27.19 Mbps | 6.44 Mbps
`4.22x slow` | **41.33 Mbps**
`1.52x fast` |
+| AES-192/GCM | 27.06 Mbps | 6.38 Mbps
`4.24x slow` | **40.41 Mbps**
`1.49x fast` |
+| AES-256/GCM | 26.68 Mbps | 6.27 Mbps
`4.26x slow` | **39.05 Mbps**
`1.46x fast` |
+| AES-128/CFB | **307 Mbps** | 50.4 Mbps
`6.1x slow` | |
+| AES-192/CFB | **288 Mbps** | 46.91 Mbps
`6.13x slow` | |
+| AES-256/CFB | **254 Mbps** | 43.66 Mbps
`5.81x slow` | |
+| AES-128/OFB | **433 Mbps** | 51.04 Mbps
`8.48x slow` | |
+| AES-192/OFB | **423 Mbps** | 47.07 Mbps
`8.99x slow` | |
+| AES-256/OFB | **364 Mbps** | 44.54 Mbps
`8.18x slow` | |
+| AES-128/XTS | **229 Mbps** | | |
+| AES-192/XTS | **224 Mbps** | | |
+| AES-256/XTS | **196 Mbps** | | |
+| AES-128/IGE | **275 Mbps** | 49.15 Mbps
`5.6x slow` | |
+| AES-192/IGE | **270 Mbps** | 45.42 Mbps
`5.94x slow` | |
+| AES-256/IGE | **238 Mbps** | 42.69 Mbps
`5.58x slow` | |
+| AES-128/PCBC | **303 Mbps** | | |
+| AES-192/PCBC | **288 Mbps** | | |
+| AES-256/PCBC | **248 Mbps** | | |
> All benchmarks are done on _AMD Ryzen 7 5800X_ processor and _3200MHz_ RAM using compiled _exe_
>
diff --git a/benchmark/aes_ige.dart b/benchmark/aes_ige.dart
new file mode 100644
index 0000000..75099a6
--- /dev/null
+++ b/benchmark/aes_ige.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2023, Sudipto Chandra
+// All rights reserved. Check LICENSE file for details.
+
+import 'dart:math';
+import 'dart:typed_data';
+
+import 'package:cipherlib/cipherlib.dart';
+import 'package:pointycastle/pointycastle.dart' as pc;
+
+import 'base.dart';
+
+Random random = Random();
+
+class CipherlibBenchmark extends Benchmark {
+ final Uint8List key;
+ final Uint8List iv;
+
+ CipherlibBenchmark(int size, int iter, int keySize)
+ : key = Uint8List.fromList(List.filled(keySize, 0x9f)),
+ iv = Uint8List.fromList(List.filled(32, 0x87)),
+ super('cipherlib', size, iter);
+
+ @override
+ void run() {
+ AES(key).ige(iv).encrypt(input);
+ }
+}
+
+class PointyCastleBenchmark extends Benchmark {
+ final Uint8List key;
+ final Uint8List iv;
+
+ PointyCastleBenchmark(int size, int iter, int keySize)
+ : key = Uint8List.fromList(List.filled(keySize, 0x9f)),
+ iv = Uint8List.fromList(List.filled(32, 0x87)),
+ super('PointyCastle', size, iter);
+
+ @override
+ void run() {
+ var inp = Uint8List.fromList(input);
+ var out = Uint8List(inp.length);
+ var instance = pc.BlockCipher('AES/IGE');
+ instance.init(
+ true,
+ pc.ParametersWithIV(pc.KeyParameter(key), iv),
+ );
+ for (int i = 0; i < inp.length; i += 16) {
+ instance.processBlock(inp, i, out, i);
+ }
+ }
+}
+
+void main() async {
+ print('--------- AES/IGE ----------');
+ final conditions = [
+ [5 << 20, 10],
+ [1 << 10, 5000],
+ [16, 100000],
+ ];
+ for (var condition in conditions) {
+ int size = condition[0];
+ int iter = condition[1];
+ print('---- message: ${formatSize(size)} | iterations: $iter ----');
+ print('[AES-128]');
+ await CipherlibBenchmark(size, iter, 16).measureDiff([
+ PointyCastleBenchmark(size, iter, 16),
+ ]);
+ print('[AES-192]');
+ await CipherlibBenchmark(size, iter, 24).measureDiff([
+ PointyCastleBenchmark(size, iter, 24),
+ ]);
+ print('[AES-256]');
+ await CipherlibBenchmark(size, iter, 32).measureDiff([
+ PointyCastleBenchmark(size, iter, 32),
+ ]);
+ print('');
+ }
+}
diff --git a/benchmark/benchmark.dart b/benchmark/benchmark.dart
index 6b51baa..64128d4 100644
--- a/benchmark/benchmark.dart
+++ b/benchmark/benchmark.dart
@@ -11,6 +11,7 @@ import 'aes_cfb.dart' as aes_cfb;
import 'aes_ctr.dart' as aes_ctr;
import 'aes_gcm.dart' as aes_gcm;
import 'aes_ofb.dart' as aes_ofb;
+import 'aes_ige.dart' as aes_ige;
import 'aes_xts.dart' as aes_xts;
import 'aes_keygen.dart' as aes_keygen;
import 'base.dart';
@@ -166,6 +167,18 @@ Future measureSymmetricCiphers() async {
"AES-256/XTS": [
aes_xts.CipherlibBenchmark(size, iter, 32),
],
+ "AES-128/IGE": [
+ aes_ige.CipherlibBenchmark(size, iter, 16),
+ aes_ige.PointyCastleBenchmark(size, iter, 16),
+ ],
+ "AES-192/IGE": [
+ aes_ige.CipherlibBenchmark(size, iter, 24),
+ aes_ige.PointyCastleBenchmark(size, iter, 24),
+ ],
+ "AES-256/IGE": [
+ aes_ige.CipherlibBenchmark(size, iter, 32),
+ aes_ige.PointyCastleBenchmark(size, iter, 32),
+ ],
"AES-128/PCBC": [
aes_pcbc.CipherlibBenchmark(size, iter, 16),
],
diff --git a/benchmark/xor.dart b/benchmark/xor.dart
index a50485f..5c17956 100644
--- a/benchmark/xor.dart
+++ b/benchmark/xor.dart
@@ -15,7 +15,7 @@ class CipherlibBenchmark extends Benchmark {
final Uint8List key;
CipherlibBenchmark(int size, int iter)
- : key = Uint8List.fromList(List.filled(1000, 0x9f)),
+ : key = Uint8List.fromList(List.filled(100, 0x9f)),
super('cipherlib', size, iter);
@override
@@ -28,7 +28,7 @@ class CipherlibStreamBenchmark extends AsyncBenchmark {
final Uint8List key;
CipherlibStreamBenchmark(int size, int iter)
- : key = Uint8List.fromList(List.filled(1000, 0x9f)),
+ : key = Uint8List.fromList(List.filled(100, 0x9f)),
super('cipherlib', size, iter);
@override
diff --git a/example/cipherlib_example.dart b/example/cipherlib_example.dart
index 2a5cc6e..3b86166 100644
--- a/example/cipherlib_example.dart
+++ b/example/cipherlib_example.dart
@@ -17,6 +17,7 @@ void main() {
print(' CFB: ${toHex(AES(key).cfb(iv).encryptString(plain))}');
print(' OFB: ${toHex(AES(key).ofb(iv).encryptString(plain))}');
print(' XTS: ${toHex(AES(key).xts(iv).encryptString(plain))}');
+ print(' IGE: ${toHex(AES(key).ige(iv).encryptString(plain))}');
print(' PCBC: ${toHex(AES(key).pcbc(iv).encryptString(plain))}');
}
print('');
diff --git a/lib/src/aes.dart b/lib/src/aes.dart
index d6bec17..1cb68f9 100644
--- a/lib/src/aes.dart
+++ b/lib/src/aes.dart
@@ -6,6 +6,7 @@ import 'package:cipherlib/src/algorithms/aes/cfb.dart';
import 'package:cipherlib/src/algorithms/aes/ctr.dart';
import 'package:cipherlib/src/algorithms/aes/ecb.dart';
import 'package:cipherlib/src/algorithms/aes/gcm.dart';
+import 'package:cipherlib/src/algorithms/aes/ige.dart';
import 'package:cipherlib/src/algorithms/aes/ofb.dart';
import 'package:cipherlib/src/algorithms/aes/pcbc.dart';
import 'package:cipherlib/src/algorithms/aes/xts.dart';
@@ -16,6 +17,7 @@ export 'package:cipherlib/src/algorithms/aes/cfb.dart';
export 'package:cipherlib/src/algorithms/aes/ctr.dart';
export 'package:cipherlib/src/algorithms/aes/ecb.dart';
export 'package:cipherlib/src/algorithms/aes/gcm.dart';
+export 'package:cipherlib/src/algorithms/aes/ige.dart';
export 'package:cipherlib/src/algorithms/aes/ofb.dart';
export 'package:cipherlib/src/algorithms/aes/pcbc.dart';
export 'package:cipherlib/src/algorithms/aes/xts.dart';
@@ -67,20 +69,10 @@ class AES {
/// Techniques][spec].
///
/// ```
- /// key
- /// |
- /// v
- /// Plaintext ---> [block cipher] ---> Ciphertext
- ///
- /// key
- /// |
- /// v
- /// Plaintext ---> [block cipher] ---> Ciphertext
- ///
- /// key
- /// |
- /// v
- /// Plaintext ---> [block cipher] ---> Ciphertext
+ /// (key)
+ /// |
+ /// v
+ /// PT ---> [AES] ---> CT
/// ```
///
/// [spec]: https://csrc.nist.gov/pubs/sp/800/38/a/final
@@ -100,20 +92,15 @@ class AES {
/// - [iv] (initialization vector) is the random 16-byte salt.
///
/// ```
- /// IV Key
- /// | |
- /// v v
- /// Plaintext ---> (XOR) ---> [block cipher] ---> Ciphertext
- /// ________________________________|
- /// | Key
- /// | |
- /// v v
- /// Plaintext ---> (XOR) ---> [block cipher] ---> Ciphertext
- /// ________________________________|
- /// | Key
- /// | |
- /// v v
- /// Plaintext ---> (XOR) ---> [block cipher] ---> Ciphertext
+ /// IV (Key)
+ /// | |
+ /// v v
+ /// PT1 ---> (XOR) ---> [AES] ---> CT1
+ /// ____________________|
+ /// | (Key)
+ /// | |
+ /// v v
+ /// PT2 ---> (XOR) ---> [AES] ---> CT2
/// ```
///
/// [spec]: https://csrc.nist.gov/pubs/sp/800/38/a/final
@@ -139,20 +126,15 @@ class AES {
/// Big-Endian order.
///
/// ```
- /// Key Plaintext
- /// | |
- /// v v
- /// -----> [block cipher] ---> (XOR) ---> Ciphertext
- ///
- /// Key Plaintext
- /// | |
- /// v v
- /// ---> [block cipher] ---> (XOR) ---> Ciphertext
- ///
- /// Key Plaintext
- /// | |
- /// v v
- /// ---> [block cipher] ---> (XOR) ---> Ciphertext
+ /// (Key) PT1
+ /// | |
+ /// v v
+ /// -----> [AES] ---> (XOR) ---> CT1
+ ///
+ /// (Key) PT2
+ /// | |
+ /// v v
+ /// ---> [AES] ---> (XOR) ---> CT2
/// ```
///
/// [spec]: https://csrc.nist.gov/pubs/sp/800/38/a/final
@@ -173,24 +155,17 @@ class AES {
/// - [sbyte] number of bytes to take per block. (Default: 16)
///
/// ```
- /// Key Plaintext (s-bit)
- /// | |
- /// v v
- /// IV ---> [block cipher] -- [>>(16-s)] --> (XOR) ---> Ciphertext
- /// | _____________________________| (s-bit)
+ /// Key PT1 (s-bit)
+ /// | |
+ /// v v
+ /// IV ---> [AES] -- [>>(16-s)] --> (XOR) ---> CT1 (s-bit)
+ /// | ______________________________|
/// | |
/// v v
- /// [<< s] -> (XOR) Key Plaintext (s-bit)
- /// ________| | |
- /// | | v v
- /// | -> [block cipher] --[>>(16-s)]--> (XOR) --> (s-bit)
- /// | ___________________________________|
- /// | |
- /// v v
- /// [<< s] -> (XOR) Key Plaintext (s-bit)
- /// | | |
- /// | v v
- /// -> [block cipher] --[>>(16-s)]--> (XOR) --> (s-bit)
+ /// [<< s] -> (XOR) (Key) PT2 (s-bit)
+ /// | | |
+ /// | v v
+ /// ---> [AES] --[>>(16-s)]--> (XOR) --> CT2 (s-bit)
/// ```
///
/// [spec]: https://csrc.nist.gov/pubs/sp/800/38/a/final
@@ -226,20 +201,16 @@ class AES {
/// - [iv] (initialization vector) is the random 16-byte salt.
///
/// ```
- /// Key Plaintext
- /// | |
- /// v v
- /// IV ---> [block cipher] ------> (XOR) ---> Ciphertext
- /// _____________________|
- /// | Key Plaintext
- /// | | |
- /// | v v
- /// ---> [block cipher] ------> (XOR) ---> Ciphertext
- /// _____________________|
- /// | Key Plaintext
- /// | | |
- /// | v v
- /// ---> [block cipher] ------> (XOR) ---> Ciphertext
+ /// (Key) PT1
+ /// | |
+ /// v v
+ /// IV ---> [AES] ------> (XOR) ---> CT1
+ /// ____________________|
+ /// |
+ /// | (Key) PT2
+ /// | | |
+ /// | v v
+ /// ---> [AES] ------> (XOR) ---> CT2
/// ```
///
/// [spec]: https://csrc.nist.gov/pubs/sp/800/38/a/final
@@ -271,22 +242,16 @@ class AES {
/// - [iv] (initialization vector) is the random 16-byte salt.
///
/// ```
- /// IV Key
- /// | |
- /// v v
- /// Plaintext ---> (XOR) ---> [block cipher] ---> Ciphertext
- /// | _________________________________|
- /// | |
- /// --> (XOR) Key
- /// | |
- /// v v
- /// Plaintext ---> (XOR) ---> [block cipher] ---> Ciphertext
- /// | _________________________________|
- /// | |
- /// --> (XOR) Key
- /// | |
- /// v v
- /// Plaintext ---> (XOR) ---> [block cipher] ---> Ciphertext
+ /// IV (Key)
+ /// | |
+ /// v v
+ /// PT1 ---> (XOR) ---> [AES] ---> CT1
+ /// | ____________________|
+ /// | |
+ /// +-----> (XOR) (Key)
+ /// | |
+ /// v v
+ /// PT2 ---> (XOR) ---> [AES] ---> CT2
/// ```
AESInPCBCMode pcbc(List iv) => AESInPCBCMode(
key,
@@ -347,4 +312,36 @@ class AES {
///
/// [spec]: https://ieeexplore.ieee.org/document/8637988
AESInXTSMode xts(List tweak) => AESInXTSMode(key, tweak);
+
+ /// The Infinite Garble Extension (IGE) mode is specifically designed to
+ /// provide error propagation, which is useful in certain cryptographic
+ /// applications.
+ ///
+ /// Error propagation is designed so that a single-bit error in the ciphertext
+ /// affects all subsequent blocks during decryption. It is possible due to the
+ /// usage of unique Initialization Vector (IV) for each pass.
+ ///
+ /// Parameters:
+ /// - [iv] (initialization vector) is the random 16-byte salt.
+ ///
+ /// ```
+ /// +----------------------------------------------+
+ /// | IV1 (Key) IV2 |
+ /// | | | | |
+ /// | v v V |
+ /// PT1 ---> (XOR) ---> [AES] ---> (XOR) ---> CT1 |
+ /// _______________________________| |
+ /// | |
+ /// | (Key) ______________|
+ /// | | |
+ /// v v v
+ /// PT2 ---> (XOR) ---> [AES] ---> (XOR) ---> CT2
+ /// ```
+ ///
+ /// [spec]: https://csrc.nist.gov/pubs/sp/800/38/a/final
+ AESInIGEMode ige(List iv) => AESInIGEMode(
+ key,
+ iv: iv,
+ padding: padding,
+ );
}
diff --git a/lib/src/algorithms/aes/cbc.dart b/lib/src/algorithms/aes/cbc.dart
index b37c43d..1fb6a2d 100644
--- a/lib/src/algorithms/aes/cbc.dart
+++ b/lib/src/algorithms/aes/cbc.dart
@@ -191,7 +191,9 @@ class AESInCBCModeDecryptSink extends CipherSink {
if (_pos != 0 || _rpos != 0) {
throw StateError('Invalid input size');
}
- p -= _padding.getPadLength(output);
+ if (p > 0) {
+ p -= _padding.getPadLength(output, p);
+ }
}
if (n == p) {
diff --git a/lib/src/algorithms/aes/ecb.dart b/lib/src/algorithms/aes/ecb.dart
index 23e9035..7926ce8 100644
--- a/lib/src/algorithms/aes/ecb.dart
+++ b/lib/src/algorithms/aes/ecb.dart
@@ -168,7 +168,9 @@ class AESInECBModeDecryptSink extends CipherSink {
if (_pos != 0 || _rpos != 0) {
throw StateError('Invalid input size');
}
- p -= _padding.getPadLength(output);
+ if (p > 0) {
+ p -= _padding.getPadLength(output, p);
+ }
}
if (n == p) {
diff --git a/lib/src/algorithms/aes/ige.dart b/lib/src/algorithms/aes/ige.dart
new file mode 100644
index 0000000..0bc742e
--- /dev/null
+++ b/lib/src/algorithms/aes/ige.dart
@@ -0,0 +1,305 @@
+// Copyright (c) 2024, Sudipto Chandra
+// All rights reserved. Check LICENSE file for details.
+
+import 'dart:typed_data';
+
+import 'package:cipherlib/src/algorithms/padding.dart';
+import 'package:cipherlib/src/core/cipher_sink.dart';
+import 'package:cipherlib/src/core/salted_cipher.dart';
+import 'package:hashlib/hashlib.dart';
+
+import '_core.dart';
+
+/// The sink used for encryption by the [AESInIGEModeEncrypt] algorithm.
+class AESInIGEModeEncryptSink extends CipherSink {
+ AESInIGEModeEncryptSink(
+ this._key,
+ this._iv,
+ this._padding,
+ ) {
+ reset();
+ }
+
+ int _pos = 0;
+ bool _closed = false;
+ final Uint8List _iv;
+ final Uint8List _key;
+ final Padding _padding;
+ final _block = Uint8List(16); // 128-bit
+ final _salt = Uint8List(32);
+ late final _key32 = Uint32List.view(_key.buffer);
+ late final _block32 = Uint32List.view(_block.buffer);
+ late final _xkey32 = AESCore.$expandEncryptionKey(_key32);
+
+ @override
+ bool get closed => _closed;
+
+ @override
+ void reset() {
+ _pos = 0;
+ _closed = false;
+ for (int i = 0; i < 16; ++i) {
+ _block[i] = _iv[i]; // iv1
+ _salt[i] = 0;
+ _salt[i + 16] = 0;
+ }
+ for (int i = 16; i < _iv.length && i < 32; ++i) {
+ _salt[i - 16] = _iv[i]; // iv2
+ }
+ }
+
+ @override
+ Uint8List add(
+ List data, [
+ int start = 0,
+ int? end,
+ bool last = false,
+ ]) {
+ if (_closed) {
+ throw StateError('The sink is closed');
+ }
+ _closed = last;
+ end ??= data.length;
+
+ int i, j, p, n;
+
+ n = _pos + end - start;
+ if (last) {
+ n += 16 - (n & 15);
+ }
+ var output = Uint8List(n);
+
+ p = 0;
+ for (i = start; i < end; ++i) {
+ _salt[_pos + 16] = data[i];
+ _block[_pos++] ^= data[i];
+ if (_pos == 16) {
+ AESCore.$encryptLE(_block32, _xkey32);
+ for (j = 0; j < 16; ++j) {
+ _block[j] ^= _salt[j];
+ _salt[j] = _salt[j + 16];
+ output[p++] = _block[j];
+ }
+ _pos = 0;
+ }
+ }
+
+ if (last) {
+ if (_padding.pad(_salt, _pos + 16)) {
+ for (; _pos < 16; _pos++) {
+ _block[_pos] ^= _salt[_pos + 16];
+ }
+ AESCore.$encryptLE(_block32, _xkey32);
+ for (j = 0; j < 16; ++j) {
+ output[p++] = _block[j] ^ _salt[j];
+ }
+ _pos = 0;
+ }
+ if (_pos != 0) {
+ throw StateError('Invalid input size');
+ }
+ }
+
+ if (n == p) {
+ return output;
+ } else if (p == 0) {
+ return Uint8List(0);
+ } else {
+ return output.sublist(0, p);
+ }
+ }
+}
+
+/// The sink used for decryption by the [AESInIGEModeDecrypt] algorithm.
+class AESInIGEModeDecryptSink extends CipherSink {
+ AESInIGEModeDecryptSink(
+ this._key,
+ this._iv,
+ this._padding,
+ ) {
+ reset();
+ }
+
+ int _pos = 0;
+ int _rpos = 0;
+ bool _closed = false;
+ final Uint8List _key;
+ final Uint8List _iv;
+ final Padding _padding;
+ late final Uint32List _key32 = Uint32List.view(_key.buffer);
+ final _block = Uint8List(16); // 128-bit
+ final _salt = Uint8List(32);
+ final _residue = Uint8List(16);
+ late final _block32 = Uint32List.view(_block.buffer);
+ late final _xkey32 = AESCore.$expandDecryptionKey(_key32);
+
+ @override
+ bool get closed => _closed;
+
+ @override
+ void reset() {
+ _pos = 0;
+ _rpos = 0;
+ _closed = false;
+ for (int i = 0; i < 16; ++i) {
+ _block[i] = 0;
+ _salt[i] = _iv[i]; // iv1
+ _salt[i + 16] = 0;
+ }
+ for (int i = 16; i < _iv.length && i < 32; ++i) {
+ _block[i - 16] = _iv[i]; //iv2
+ }
+ }
+
+ @override
+ Uint8List add(
+ List data, [
+ int start = 0,
+ int? end,
+ bool last = false,
+ ]) {
+ if (_closed) {
+ throw StateError('The sink is closed');
+ }
+ _closed = last;
+ end ??= data.length;
+
+ int i, j, k, p, n;
+
+ n = _rpos + end - start;
+ var output = Uint8List(n);
+
+ p = 0;
+ for (i = start; i < end; ++i) {
+ _salt[_pos + 16] = data[i];
+ _block[_pos++] ^= data[i];
+ if (_pos == 16) {
+ AESCore.$decryptLE(_block32, _xkey32);
+ for (j = 0; j < 16; ++j) {
+ if (_rpos == 16) {
+ for (k = 0; k < 16; ++k) {
+ output[p++] = _residue[k];
+ }
+ _rpos = 0;
+ }
+ _block[j] ^= _salt[j];
+ _salt[j] = _salt[j + 16];
+ _residue[_rpos++] = _block[j];
+ }
+ _pos = 0;
+ }
+ }
+
+ if (last) {
+ if (_rpos == 16) {
+ for (k = 0; k < 16; ++k) {
+ output[p++] = _residue[k];
+ }
+ _rpos = 0;
+ }
+ if (_pos != 0 || _rpos != 0) {
+ throw StateError('Invalid input size');
+ }
+ if (p > 0) {
+ p -= _padding.getPadLength(output, p);
+ }
+ }
+
+ if (n == p) {
+ return output;
+ } else if (p == 0) {
+ return Uint8List(0);
+ } else {
+ return output.sublist(0, p);
+ }
+ }
+}
+
+/// Provides encryption for AES cipher in IGE mode.
+class AESInIGEModeEncrypt extends SaltedCipher {
+ @override
+ String get name => "AES#encrypt/IGE/${padding.name}";
+
+ /// Key for the cipher
+ final Uint8List key;
+
+ /// Padding scheme for the input message
+ final Padding padding;
+
+ const AESInIGEModeEncrypt(
+ this.key,
+ Uint8List iv, [
+ this.padding = Padding.pkcs7,
+ ]) : super(iv);
+
+ @override
+ @pragma('vm:prefer-inline')
+ AESInIGEModeEncryptSink createSink() =>
+ AESInIGEModeEncryptSink(key, iv, padding);
+}
+
+/// Provides decryption for AES cipher in IGE mode.
+class AESInIGEModeDecrypt extends SaltedCipher {
+ @override
+ String get name => "AES#decrypt/IGE/${padding.name}";
+
+ /// Key for the cipher
+ final Uint8List key;
+
+ /// Padding scheme for the output message
+ final Padding padding;
+
+ const AESInIGEModeDecrypt(
+ this.key,
+ Uint8List iv, [
+ this.padding = Padding.pkcs7,
+ ]) : super(iv);
+
+ @override
+ @pragma('vm:prefer-inline')
+ AESInIGEModeDecryptSink createSink() =>
+ AESInIGEModeDecryptSink(key, iv, padding);
+}
+
+/// Provides encryption and decryption for AES cipher in IGE mode.
+class AESInIGEMode extends SaltedCollateCipher {
+ @override
+ String get name => "AES/IGE/${padding.name}";
+
+ @override
+ final AESInIGEModeEncrypt encryptor;
+
+ @override
+ final AESInIGEModeDecrypt decryptor;
+
+ const AESInIGEMode._({
+ required this.encryptor,
+ required this.decryptor,
+ });
+
+ /// Creates AES cipher in IGE mode.
+ ///
+ /// Parameters:
+ /// - [key] The key for encryption and decryption
+ /// - [iv] 128-bit random initialization vector or salt
+ /// - [padding] The padding scheme for the messages
+ factory AESInIGEMode(
+ List key, {
+ List? iv,
+ Padding padding = Padding.pkcs7,
+ }) {
+ iv ??= randomBytes(32);
+ if (iv.length < 16) {
+ throw StateError('IV must be at least 16-bytes');
+ }
+ var iv8 = iv is Uint8List ? iv : Uint8List.fromList(iv);
+ var key8 = key is Uint8List ? key : Uint8List.fromList(key);
+ return AESInIGEMode._(
+ encryptor: AESInIGEModeEncrypt(key8, iv8, padding),
+ decryptor: AESInIGEModeDecrypt(key8, iv8, padding),
+ );
+ }
+
+ /// Padding scheme for the messages
+ Padding get padding => encryptor.padding;
+}
diff --git a/lib/src/algorithms/aes/pcbc.dart b/lib/src/algorithms/aes/pcbc.dart
index 11d4669..0d191fe 100644
--- a/lib/src/algorithms/aes/pcbc.dart
+++ b/lib/src/algorithms/aes/pcbc.dart
@@ -189,7 +189,9 @@ class AESInPCBCModeDecryptSink extends CipherSink {
if (_pos != 0 || _rpos != 0) {
throw StateError('Invalid input size');
}
- p -= _padding.getPadLength(output);
+ if (p > 0) {
+ p -= _padding.getPadLength(output, p);
+ }
}
if (n == p) {
diff --git a/lib/src/algorithms/xor.dart b/lib/src/algorithms/xor.dart
index 81bdb3b..b1f5040 100644
--- a/lib/src/algorithms/xor.dart
+++ b/lib/src/algorithms/xor.dart
@@ -45,7 +45,7 @@ class XORSink extends CipherSink {
if (_pos == _key.length) {
_pos = 0;
}
- result[i] = data[i] ^ _key[_pos];
+ result[i] = data[i] ^ _key[_pos++];
}
return result;
}
@@ -76,16 +76,4 @@ class XOR extends Cipher {
@override
@pragma('vm:prefer-inline')
XORSink createSink() => XORSink(key);
-
- @override
- Uint8List convert(List message) {
- var result = Uint8List.fromList(message);
- for (int i = 0, j = 0; i < message.length; ++i) {
- result[i] ^= key[j++];
- if (j == key.length) {
- j = 0;
- }
- }
- return result;
- }
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 0020ef6..b7a206c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,14 +1,14 @@
name: cipherlib
description: Implementations of cryptographic algorithms for encryption and decryption in Dart.
-version: 0.0.10
+version: 0.0.11
repository: https://github.com/bitanon/cipherlib
environment:
sdk: '>=2.14.0 <4.0.0'
dependencies:
- hashlib: ^1.19.1
- hashlib_codecs: ^2.2.0
+ hashlib: ^1.19.2
+ hashlib_codecs: ^2.5.0
dev_dependencies:
lints: any
diff --git a/test/aes_cbc_test.dart b/test/aes_cbc_test.dart
index 9c55365..1fab99e 100644
--- a/test/aes_cbc_test.dart
+++ b/test/aes_cbc_test.dart
@@ -95,11 +95,14 @@ void main() {
var aes = AES.noPadding(Uint8List(16)).cbc(Uint8List(16));
expect(() => aes.encrypt(Uint8List(10)), throwsStateError);
expect(() => aes.decrypt(Uint8List(10)), throwsStateError);
+ expect(() => aes.encrypt(Uint8List(17)), throwsStateError);
+ expect(() => aes.decrypt(Uint8List(17)), throwsStateError);
});
test('throws error on invalid salt size', () {
var aes = AES(Uint8List(16));
expect(() => aes.cbc(Uint8List(15)).encrypt([0]), throwsStateError);
expect(() => aes.cbc(Uint8List(8)).decrypt([0]), throwsStateError);
+ expect(aes.cbc(Uint8List(16)).encrypt([]).length, 16);
});
group('empty message', () {
diff --git a/test/aes_ecb_test.dart b/test/aes_ecb_test.dart
index 2fbabf0..4baf18f 100644
--- a/test/aes_ecb_test.dart
+++ b/test/aes_ecb_test.dart
@@ -107,6 +107,8 @@ void main() {
var aes = AES.noPadding(Uint8List(16)).ecb();
expect(() => aes.encrypt(Uint8List(10)), throwsStateError);
expect(() => aes.decrypt(Uint8List(10)), throwsStateError);
+ expect(() => aes.encrypt(Uint8List(17)), throwsStateError);
+ expect(() => aes.decrypt(Uint8List(17)), throwsStateError);
});
group('empty message', () {
diff --git a/test/aes_ige_test.dart b/test/aes_ige_test.dart
new file mode 100644
index 0000000..c37fdbe
--- /dev/null
+++ b/test/aes_ige_test.dart
@@ -0,0 +1,145 @@
+// Copyright (c) 2024, Sudipto Chandra
+// All rights reserved. Check LICENSE file for details.
+
+import 'dart:typed_data';
+
+import 'package:cipherlib/cipherlib.dart';
+import 'package:hashlib/hashlib.dart';
+import 'package:hashlib_codecs/hashlib_codecs.dart';
+import 'package:test/test.dart';
+
+void main() {
+ test('throws error on invalid input size', () {
+ var aes = AES.noPadding(Uint8List(16)).ige(Uint8List(32));
+ expect(() => aes.encrypt(Uint8List(10)), throwsStateError);
+ expect(() => aes.decrypt(Uint8List(10)), throwsStateError);
+ expect(() => aes.encrypt(Uint8List(17)), throwsStateError);
+ expect(() => aes.decrypt(Uint8List(17)), throwsStateError);
+ });
+ test('throws error on invalid salt size', () {
+ var aes = AES(Uint8List(16));
+ expect(() => aes.ige(Uint8List(0)).decrypt([0]), throwsStateError);
+ expect(() => aes.ige(Uint8List(15)).encrypt([0]), throwsStateError);
+ expect(aes.ige(Uint8List(16)).encrypt([]).length, 16);
+ });
+
+ group('empty message', () {
+ var aes = AES.noPadding(Uint8List(32)).ige(Uint8List(32));
+ test('encrypt', () {
+ var actual = aes.encrypt([]);
+ expect(toHex(actual), equals(toHex([])));
+ });
+ test('decrypt', () {
+ var reverse = aes.decrypt([]);
+ expect(toHex(reverse), equals(toHex([])));
+ });
+ });
+
+ group('encryption <-> decryption', () {
+ test("128-bit", () {
+ var key = randomBytes(16);
+ for (int j = 0; j < 100; j++) {
+ var inp = randomBytes(j);
+ var iv = randomBytes(32);
+ var cipher = AES(key).ige(iv).encrypt(inp);
+ var plain = AES(key).ige(iv).decrypt(cipher);
+ expect(toHex(plain), equals(toHex(inp)), reason: '[size: $j]');
+ }
+ });
+ test("192-bit", () {
+ var key = randomBytes(24);
+ for (int j = 0; j < 100; j++) {
+ var inp = randomBytes(j);
+ var iv = randomBytes(32);
+ var cipher = AES(key).ige(iv).encrypt(inp);
+ var plain = AES(key).ige(iv).decrypt(cipher);
+ expect(toHex(plain), equals(toHex(inp)), reason: '[size: $j]');
+ }
+ });
+ test("256-bit", () {
+ var key = randomBytes(32);
+ for (int j = 0; j < 100; j++) {
+ var inp = randomBytes(j);
+ var iv = randomBytes(32);
+ var cipher = AES(key).ige(iv).encrypt(inp);
+ var plain = AES(key).ige(iv).decrypt(cipher);
+ expect(toHex(plain), equals(toHex(inp)), reason: '[size: $j]');
+ }
+ });
+ });
+
+ group('sink test', () {
+ test('encryption', () {
+ var key = randomBytes(32);
+ for (int j = 0; j < 100; j++) {
+ var iv = randomBytes(32);
+ final aes = AES(key).ige(iv);
+
+ var input = randomBytes(j);
+ var cipher = aes.encrypt(input);
+
+ var enc = aes.encryptor.createSink();
+ var output = [];
+ for (int i = 0; i < input.length; i += 13) {
+ output.addAll(enc.add(input.skip(i).take(13).toList()));
+ }
+ output.addAll(enc.close());
+ expect(toHex(output), equals(toHex(cipher)), reason: '[size: $j]');
+
+ var plain = aes.decrypt(output);
+ expect(toHex(plain), equals(toHex(input)), reason: '[size: $j]');
+ }
+ });
+ test('decryption', () {
+ var key = randomBytes(32);
+ for (int j = 0; j < 100; j++) {
+ var iv = randomBytes(32);
+ final aes = AES(key).ige(iv);
+
+ var input = randomBytes(j);
+ var cipher = aes.encrypt(input);
+
+ var dec = aes.decryptor.createSink();
+ var output = [];
+ for (int i = 0; i < cipher.length; i += 23) {
+ output.addAll(dec.add(cipher.skip(i).take(23).toList()));
+ }
+ output.addAll(dec.close());
+ expect(toHex(output), equals(toHex(input)), reason: '[size: $j]');
+ }
+ });
+ test('encryption + decryption', () {
+ var key = randomBytes(32);
+ for (int j = 0; j < 100; j++) {
+ var iv = randomBytes(32);
+ var input = randomBytes(j);
+
+ final aes = AES(key).ige(iv);
+ var enc = aes.encryptor.createSink();
+ var dec = aes.decryptor.createSink();
+
+ var output = [];
+ for (int i = 0; i < input.length; i += 23) {
+ var part = input.skip(i).take(23).toList();
+ output.addAll(dec.add(enc.add(part)));
+ }
+ output.addAll(dec.add(enc.close()));
+ output.addAll(dec.close());
+ expect(toHex(output), equals(toHex(input)), reason: '[size: $j]');
+ }
+ });
+ });
+
+ test('reset iv', () {
+ var iv = randomBytes(32);
+ var key = randomBytes(24);
+ var aes = AES(key).ige(iv);
+ for (int j = 0; j < 100; j++) {
+ aes.resetIV();
+ var inp = randomBytes(j);
+ var cipher = aes.encrypt(inp);
+ var plain = aes.decrypt(cipher);
+ expect(toHex(plain), equals(toHex(inp)), reason: '[size: $j]');
+ }
+ });
+}
diff --git a/test/aes_pcbc_test.dart b/test/aes_pcbc_test.dart
index 98cdb6b..070f863 100644
--- a/test/aes_pcbc_test.dart
+++ b/test/aes_pcbc_test.dart
@@ -13,11 +13,14 @@ void main() {
var aes = AES.noPadding(Uint8List(16)).pcbc(Uint8List(16));
expect(() => aes.encrypt(Uint8List(10)), throwsStateError);
expect(() => aes.decrypt(Uint8List(10)), throwsStateError);
+ expect(() => aes.encrypt(Uint8List(17)), throwsStateError);
+ expect(() => aes.decrypt(Uint8List(17)), throwsStateError);
});
test('throws error on invalid salt size', () {
var aes = AES(Uint8List(16));
expect(() => aes.pcbc(Uint8List(15)).encrypt([0]), throwsStateError);
expect(() => aes.pcbc(Uint8List(8)).decrypt([0]), throwsStateError);
+ expect(aes.pcbc(Uint8List(16)).encrypt([]).length, 16);
});
group('encryption <-> decryption', () {
diff --git a/test/compare_test.dart b/test/compare_test.dart
index b5f72fb..7a4a5f9 100644
--- a/test/compare_test.dart
+++ b/test/compare_test.dart
@@ -185,6 +185,54 @@ void main() {
});
});
+ group('AES/IGE', () {
+ test('pointycastle: encryption with 128-bit key', () {
+ var key = randomBytes(16);
+ for (int j = 16; j < 300; j += 16) {
+ var text = randomBytes(j);
+ var iv = randomBytes(32);
+ var result = my.AES.noPadding(key).ige(iv).encrypt(text);
+ var instance = pc.BlockCipher('AES/IGE');
+ instance.init(true, pc.ParametersWithIV(pc.KeyParameter(key), iv));
+ var out = Uint8List(j);
+ for (int i = 0; i < j; i += 16) {
+ instance.processBlock(text, i, out, i);
+ }
+ expect(toHex(out), equals(toHex(result)), reason: '[size: $j]');
+ }
+ });
+ test('pointycastle: encryption with 192-bit key', () {
+ var key = randomBytes(24);
+ for (int j = 16; j < 300; j += 16) {
+ var text = randomBytes(j);
+ var iv = randomBytes(32);
+ var result = my.AES.noPadding(key).ige(iv).encrypt(text);
+ var instance = pc.BlockCipher('AES/IGE');
+ instance.init(true, pc.ParametersWithIV(pc.KeyParameter(key), iv));
+ var out = Uint8List(j);
+ for (int i = 0; i < j; i += 16) {
+ instance.processBlock(text, i, out, i);
+ }
+ expect(toHex(out), equals(toHex(result)), reason: '[size: $j]');
+ }
+ });
+ test('pointycastle: encryption with 256-bit key', () {
+ var key = randomBytes(32);
+ for (int j = 16; j < 300; j += 16) {
+ var text = randomBytes(j);
+ var iv = randomBytes(32);
+ var result = my.AES.noPadding(key).ige(iv).encrypt(text);
+ var instance = pc.BlockCipher('AES/IGE');
+ instance.init(true, pc.ParametersWithIV(pc.KeyParameter(key), iv));
+ var out = Uint8List(j);
+ for (int i = 0; i < j; i += 16) {
+ instance.processBlock(text, i, out, i);
+ }
+ expect(toHex(out), equals(toHex(result)), reason: '[size: $j]');
+ }
+ });
+ });
+
group('AES/CFB-64', () {
test('pointycastle: encryption with 128-bit key', () {
var key = randomBytes(16);
diff --git a/test/xor_test.dart b/test/xor_test.dart
index a402619..601d086 100644
--- a/test/xor_test.dart
+++ b/test/xor_test.dart
@@ -4,13 +4,14 @@
import 'dart:typed_data';
import 'package:cipherlib/cipherlib.dart';
+import 'package:hashlib_codecs/hashlib_codecs.dart';
import 'package:test/test.dart';
import 'utils.dart';
void main() {
test('empty key with empty message', () {
- expect(xor([], []), equals([]));
+ expect(() => xor([], []), throwsArgumentError);
});
test('empty key with some message', () {
expect(() => xor([1], []), throwsArgumentError);
@@ -18,6 +19,15 @@ void main() {
test('empty message', () {
expect(xor([], [1]), equals([]));
});
+ test('known message', () {
+ var key = 'key'.codeUnits;
+ var plain = 'plaintext'.codeUnits;
+ var cipher = fromHex('1b0918020b0d0e1d0d');
+ var out = xor(plain, key);
+ expect(toHex(out), equals(toHex(cipher)));
+ var rev = xor(cipher, key);
+ expect(toHex(rev), equals(toHex(plain)));
+ });
test('encryption <-> decryption (convert)', () {
for (int i = 1; i < 100; i += 10) {
var key = randomNumbers(i);