snow-20130616/0000755000076400007640000000000012162302251011762 5ustar mkwanmkwansnow-20130616/ChangeLog0000644000076400007640000000021112157312026013533 0ustar mkwanmkwan2013-06-16 Matthew Kwan - compress.c: Fixed some fprintf format warnings. - Makefile: Added new compile flags. snow-20130616/huffcode.h0000644000076400007640000002445012157331570013735 0ustar mkwanmkwan/* * Pre-calculated Huffman coding table for ASCII. * * Copyright (C) 1999 Matthew Kwan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * For license text, see https://spdx.org/licenses/Apache-2.0>. */ #ifndef _HUFFCODE_H #define _HUFFCODE_H "010011101110011001000", /* 0 - 0.00% */ "010011101110011001001", /* 1 - 0.00% */ "010011101110011001010", /* 2 - 0.00% */ "010011101110011001011", /* 3 - 0.00% */ "010011101110011001100", /* 4 - 0.00% */ "010011101110011001101", /* 5 - 0.00% */ "010011101110011001110", /* 6 - 0.00% */ "010011101110011001111", /* 7 - 0.00% */ "101100010101", /* 8 - 0.03% */ "0100100", /* 9 - 0.62% */ "101101", /* 10 - 1.93% */ "010011101110011010000", /* 11 - 0.00% */ "0100111011100111", /* 12 - 0.00% */ "010011101110011010001", /* 13 - 0.00% */ "010011101110011010010", /* 14 - 0.00% */ "010011101110011010011", /* 15 - 0.00% */ "010011101110011010100", /* 16 - 0.00% */ "010011101110011010101", /* 17 - 0.00% */ "010011101110011010110", /* 18 - 0.00% */ "010011101110011010111", /* 19 - 0.00% */ "010011101110011011000", /* 20 - 0.00% */ "010011101110011011001", /* 21 - 0.00% */ "010011101110011011010", /* 22 - 0.00% */ "010011101110011011011", /* 23 - 0.00% */ "010011101110011011100", /* 24 - 0.00% */ "010011101110011011101", /* 25 - 0.00% */ "010011101110011011110", /* 26 - 0.00% */ "010011101110001", /* 27 - 0.00% */ "010011101110011011111", /* 28 - 0.00% */ "01001110111000000000", /* 29 - 0.00% */ "01001110111000000001", /* 30 - 0.00% */ "01001110111000000010", /* 31 - 0.00% */ "111", /* ' ' - 17.61% */ "0100101000", /* '!' - 0.08% */ "101100100", /* '"' - 0.23% */ "10111111111", /* '#' - 0.07% */ "101111010010", /* '$' - 0.03% */ "1011000101000", /* '%' - 0.01% */ "0010100010101", /* '&' - 0.01% */ "00101011", /* ''' - 0.31% */ "101111110", /* '(' - 0.26% */ "00100011", /* ')' - 0.28% */ "010010101", /* '*' - 0.16% */ "101111010011", /* '+' - 0.03% */ "1010110", /* ',' - 0.80% */ "10111110", /* '-' - 0.49% */ "101000", /* '.' - 1.51% */ "101111001", /* '/' - 0.24% */ "0010000", /* '0' - 0.53% */ "01001011", /* '1' - 0.32% */ "101100101", /* '2' - 0.23% */ "001010101", /* '3' - 0.15% */ "001010011", /* '4' - 0.15% */ "1011110111", /* '5' - 0.12% */ "1011001100", /* '6' - 0.11% */ "0100101001", /* '7' - 0.08% */ "1010011001", /* '8' - 0.10% */ "001010000", /* '9' - 0.14% */ "101111000", /* ':' - 0.24% */ "10111111110", /* ';' - 0.07% */ "01001110110", /* '<' - 0.04% */ "10100101010", /* '=' - 0.04% */ "10111101000", /* '>' - 0.06% */ "1010010100", /* '?' - 0.09% */ "0010100011", /* '@' - 0.07% */ "01001111", /* 'A' - 0.34% */ "1011110110", /* 'B' - 0.12% */ "101100011", /* 'C' - 0.22% */ "101001101", /* 'D' - 0.20% */ "00100010", /* 'E' - 0.27% */ "001010010", /* 'F' - 0.14% */ "1011000000", /* 'G' - 0.10% */ "1011001101", /* 'H' - 0.12% */ "0111000", /* 'I' - 0.68% */ "10110000011", /* 'J' - 0.05% */ "10110001011", /* 'K' - 0.06% */ "001010100", /* 'L' - 0.15% */ "101100111", /* 'M' - 0.23% */ "101001011", /* 'N' - 0.19% */ "101100001", /* 'O' - 0.22% */ "010011100", /* 'P' - 0.16% */ "1010011110001", /* 'Q' - 0.01% */ "101001110", /* 'R' - 0.20% */ "10100100", /* 'S' - 0.35% */ "10101110", /* 'T' - 0.41% */ "1011110101", /* 'U' - 0.12% */ "10100111101", /* 'V' - 0.05% */ "1011000100", /* 'W' - 0.11% */ "10110000010", /* 'X' - 0.05% */ "0100111010", /* 'Y' - 0.08% */ "010011101111", /* 'Z' - 0.02% */ "101001111001", /* '[' - 0.03% */ "001010001011", /* '\' - 0.02% */ "101001010111", /* ']' - 0.03% */ "1011000101001", /* '^' - 0.01% */ "10111111100", /* '_' - 0.06% */ "00101000100", /* '`' - 0.03% */ "0101", /* 'a' - 5.17% */ "001001", /* 'b' - 1.16% */ "110110", /* 'c' - 2.14% */ "01000", /* 'd' - 2.46% */ "1100", /* 'e' - 8.17% */ "101010", /* 'f' - 1.58% */ "011101", /* 'g' - 1.42% */ "10001", /* 'h' - 2.92% */ "0011", /* 'i' - 4.84% */ "1010011111", /* 'j' - 0.10% */ "0100110", /* 'k' - 0.67% */ "01111", /* 'l' - 2.90% */ "101110", /* 'm' - 1.94% */ "0001", /* 'n' - 4.66% */ "0110", /* 'o' - 5.51% */ "100001", /* 'p' - 1.47% */ "10111111101", /* 'q' - 0.07% */ "11010", /* 'r' - 4.10% */ "0000", /* 's' - 4.36% */ "1001", /* 't' - 6.15% */ "110111", /* 'u' - 2.21% */ "0111001", /* 'v' - 0.70% */ "001011", /* 'w' - 1.25% */ "10101111", /* 'x' - 0.42% */ "100000", /* 'y' - 1.43% */ "1010011000", /* 'z' - 0.10% */ "1010011110000", /* '{' - 0.01% */ "101001010110", /* '|' - 0.02% */ "0100111011101", /* '}' - 0.01% */ "0010100010100", /* '~' - 0.01% */ "01001110111000000011", /* 127 - 0.00% */ "010011101110000001000", /* 128 - 0.00% */ "010011101110000001001", /* 129 - 0.00% */ "010011101110000001010", /* 130 - 0.00% */ "010011101110000001011", /* 131 - 0.00% */ "010011101110000001100", /* 132 - 0.00% */ "010011101110000001101", /* 133 - 0.00% */ "010011101110000001110", /* 134 - 0.00% */ "010011101110000001111", /* 135 - 0.00% */ "010011101110000010000", /* 136 - 0.00% */ "010011101110000010001", /* 137 - 0.00% */ "010011101110000010010", /* 138 - 0.00% */ "010011101110000010011", /* 139 - 0.00% */ "010011101110000010100", /* 140 - 0.00% */ "010011101110000010101", /* 141 - 0.00% */ "010011101110000010110", /* 142 - 0.00% */ "010011101110000010111", /* 143 - 0.00% */ "010011101110000011000", /* 144 - 0.00% */ "010011101110000011001", /* 145 - 0.00% */ "010011101110000011010", /* 146 - 0.00% */ "010011101110000011011", /* 147 - 0.00% */ "010011101110000011100", /* 148 - 0.00% */ "010011101110000011101", /* 149 - 0.00% */ "010011101110000011110", /* 150 - 0.00% */ "010011101110000011111", /* 151 - 0.00% */ "010011101110000100000", /* 152 - 0.00% */ "010011101110000100001", /* 153 - 0.00% */ "010011101110000100010", /* 154 - 0.00% */ "010011101110000100011", /* 155 - 0.00% */ "010011101110000100100", /* 156 - 0.00% */ "010011101110000100101", /* 157 - 0.00% */ "010011101110000100110", /* 158 - 0.00% */ "010011101110000100111", /* 159 - 0.00% */ "010011101110000101000", /* 160 - 0.00% */ "010011101110000101001", /* 161 - 0.00% */ "010011101110000101010", /* 162 - 0.00% */ "010011101110000101011", /* 163 - 0.00% */ "010011101110000101100", /* 164 - 0.00% */ "010011101110000101101", /* 165 - 0.00% */ "010011101110000101110", /* 166 - 0.00% */ "010011101110000101111", /* 167 - 0.00% */ "010011101110000110000", /* 168 - 0.00% */ "010011101110000110001", /* 169 - 0.00% */ "010011101110000110010", /* 170 - 0.00% */ "010011101110000110011", /* 171 - 0.00% */ "010011101110000110100", /* 172 - 0.00% */ "010011101110000110101", /* 173 - 0.00% */ "010011101110000110110", /* 174 - 0.00% */ "010011101110000110111", /* 175 - 0.00% */ "010011101110000111000", /* 176 - 0.00% */ "010011101110000111001", /* 177 - 0.00% */ "010011101110000111010", /* 178 - 0.00% */ "010011101110000111011", /* 179 - 0.00% */ "010011101110000111100", /* 180 - 0.00% */ "010011101110000111101", /* 181 - 0.00% */ "010011101110000111110", /* 182 - 0.00% */ "010011101110000111111", /* 183 - 0.00% */ "010011101110010000000", /* 184 - 0.00% */ "010011101110010000001", /* 185 - 0.00% */ "010011101110010000010", /* 186 - 0.00% */ "010011101110010000011", /* 187 - 0.00% */ "010011101110010000100", /* 188 - 0.00% */ "010011101110010000101", /* 189 - 0.00% */ "010011101110010000110", /* 190 - 0.00% */ "010011101110010000111", /* 191 - 0.00% */ "010011101110010001000", /* 192 - 0.00% */ "010011101110010001001", /* 193 - 0.00% */ "010011101110010001010", /* 194 - 0.00% */ "010011101110010001011", /* 195 - 0.00% */ "010011101110010001100", /* 196 - 0.00% */ "010011101110010001101", /* 197 - 0.00% */ "010011101110010001110", /* 198 - 0.00% */ "010011101110010001111", /* 199 - 0.00% */ "010011101110010010000", /* 200 - 0.00% */ "010011101110010010001", /* 201 - 0.00% */ "010011101110010010010", /* 202 - 0.00% */ "010011101110010010011", /* 203 - 0.00% */ "010011101110010010100", /* 204 - 0.00% */ "010011101110010010101", /* 205 - 0.00% */ "010011101110010010110", /* 206 - 0.00% */ "010011101110010010111", /* 207 - 0.00% */ "010011101110010011000", /* 208 - 0.00% */ "010011101110010011001", /* 209 - 0.00% */ "010011101110010011010", /* 210 - 0.00% */ "010011101110010011011", /* 211 - 0.00% */ "010011101110010011100", /* 212 - 0.00% */ "010011101110010011101", /* 213 - 0.00% */ "010011101110010011110", /* 214 - 0.00% */ "010011101110010011111", /* 215 - 0.00% */ "010011101110010100000", /* 216 - 0.00% */ "010011101110010100001", /* 217 - 0.00% */ "010011101110010100010", /* 218 - 0.00% */ "010011101110010100011", /* 219 - 0.00% */ "010011101110010100100", /* 220 - 0.00% */ "010011101110010100101", /* 221 - 0.00% */ "010011101110010100110", /* 222 - 0.00% */ "010011101110010100111", /* 223 - 0.00% */ "010011101110010101000", /* 224 - 0.00% */ "010011101110010101001", /* 225 - 0.00% */ "010011101110010101010", /* 226 - 0.00% */ "010011101110010101011", /* 227 - 0.00% */ "010011101110010101100", /* 228 - 0.00% */ "010011101110010101101", /* 229 - 0.00% */ "010011101110010101110", /* 230 - 0.00% */ "010011101110010101111", /* 231 - 0.00% */ "010011101110010110000", /* 232 - 0.00% */ "010011101110010110001", /* 233 - 0.00% */ "010011101110010110010", /* 234 - 0.00% */ "010011101110010110011", /* 235 - 0.00% */ "010011101110010110100", /* 236 - 0.00% */ "010011101110010110101", /* 237 - 0.00% */ "010011101110010110110", /* 238 - 0.00% */ "010011101110010110111", /* 239 - 0.00% */ "010011101110010111000", /* 240 - 0.00% */ "010011101110010111001", /* 241 - 0.00% */ "010011101110010111010", /* 242 - 0.00% */ "010011101110010111011", /* 243 - 0.00% */ "010011101110010111100", /* 244 - 0.00% */ "010011101110010111101", /* 245 - 0.00% */ "010011101110010111110", /* 246 - 0.00% */ "010011101110010111111", /* 247 - 0.00% */ "010011101110011000000", /* 248 - 0.00% */ "010011101110011000001", /* 249 - 0.00% */ "010011101110011000010", /* 250 - 0.00% */ "010011101110011000011", /* 251 - 0.00% */ "010011101110011000100", /* 252 - 0.00% */ "010011101110011000101", /* 253 - 0.00% */ "010011101110011000110", /* 254 - 0.00% */ "010011101110011000111" /* 255 - 0.00% */ #endif snow-20130616/Makefile0000644000076400007640000000144312157331202013426 0ustar mkwanmkwan# Rudimentary makefile for the SNOW steganography program. # # Copyright (C) 1999 Matthew Kwan # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # For license text, see https://spdx.org/licenses/Apache-2.0>. CC ?= gcc CFLAGS ?= -O OBJ = main.o encrypt.o ice.o compress.o encode.o snow: $(OBJ) $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) clean: rm -f $(OBJ) snow # End of file snow-20130616/COPYING0000644000076400007640000002613611722522676013045 0ustar mkwanmkwan Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. snow-20130616/compress.c0000644000076400007640000001117712157331202013772 0ustar mkwanmkwan/* * Compression routines for the SNOW steganography program. * Uses simple Huffman coding. * * Copyright (C) 1999 Matthew Kwan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * For license text, see https://spdx.org/licenses/Apache-2.0>. */ #include "snow.h" #include /* * The Huffman codes. */ static const char *huffcodes[256] = { #include "huffcode.h" }; /* * Local variables used for compression. */ static int compress_bit_count; static int compress_value; static unsigned long compress_bits_in; static unsigned long compress_bits_out; /* * Initialize the compression routines. */ void compress_init (void) { compress_bit_count = 0; compress_value = 0; compress_bits_in = 0; compress_bits_out = 0; encrypt_init (); } /* * Compress a single bit. */ BOOL compress_bit ( int bit, FILE *inf, FILE *outf ) { if (!compress_flag) return (encrypt_bit (bit, inf, outf)); compress_bits_in++; compress_value = (compress_value << 1) | bit; if (++compress_bit_count == 8) { const char *s; for (s = huffcodes[compress_value]; *s != '\0'; s++) { int bit; if (*s == '1') bit = 1; else if (*s == '0') bit = 0; else { fprintf (stderr, "Illegal Huffman character '%c'\n", *s); return (FALSE); } if (!encrypt_bit (bit, inf, outf)) return (FALSE); compress_bits_out++; } compress_value = 0; compress_bit_count = 0; } return (TRUE); } /* * Flush the contents of the compression routines. */ BOOL compress_flush ( FILE *inf, FILE *outf ) { if (compress_bit_count != 0 && !quiet_flag) fprintf (stderr, "Warning: residual of %d bits not compressed\n", compress_bit_count); if (compress_bits_out > 0 && !quiet_flag) { double cpc = (double) (compress_bits_in - compress_bits_out) / (double) compress_bits_in * 100.0; if (cpc < 0.0) fprintf (stderr, "Compression enlarged data by %.2f%% - recommend not using compression\n", -cpc); else fprintf (stderr, "Compressed by %.2f%%\n", cpc); } return (encrypt_flush (inf, outf)); } /* * Local variables used for output. */ static int output_bit_count; static int output_value; /* * Initialize the output variables. */ static void output_init (void) { output_bit_count = 0; output_value = 0; } /* * Output a single bit. */ static BOOL output_bit ( int bit, FILE *outf ) { output_value = (output_value << 1) | bit; if (++output_bit_count == 8) { if (fputc (output_value, outf) == EOF) { perror ("Output file"); return (FALSE); } output_value = 0; output_bit_count = 0; } return (TRUE); } /* * Flush the contents of the output routines. */ static BOOL output_flush ( FILE *outf ) { if (output_bit_count > 2 && !quiet_flag) fprintf (stderr, "Warning: residual of %d bits not output\n", output_bit_count); return (TRUE); } /* * Local variables used for uncompression. */ static int uncompress_bit_count; static char uncompress_value[256]; /* * Initialize the uncompression routines. */ void uncompress_init (void) { uncompress_bit_count = 0; output_init (); } /* * Find the Huffman code string that matches. */ static int huffcode_find ( const char *str ) { int i; for (i=0; i<256; i++) if (strcmp (str, huffcodes[i]) == 0) return (i); return (-1); } /* * Uncompress a single bit. */ BOOL uncompress_bit ( int bit, FILE *outf ) { int code; if (!compress_flag) return (output_bit (bit, outf)); uncompress_value[uncompress_bit_count++] = bit ? '1' : '0'; uncompress_value[uncompress_bit_count] = '\0'; if ((code = huffcode_find (uncompress_value)) >= 0) { int i; for (i=0; i<8; i++) { int b = ((code & (128 >> i)) != 0) ? 1 : 0; if (!output_bit (b, outf)) return (FALSE); } uncompress_bit_count = 0; } if (uncompress_bit_count >= 255) { fprintf (stderr, "Error: Huffman uncompress buffer overflow\n"); return (FALSE); } return (TRUE); } /* * Flush the contents of the uncompression routines. */ BOOL uncompress_flush ( FILE *outf ) { if (uncompress_bit_count > 2 && !quiet_flag) fprintf (stderr, "Warning: residual of %d bits not uncompressed\n", uncompress_bit_count); return (output_flush (outf)); } snow-20130616/encode.c0000644000076400007640000002170212157331202013367 0ustar mkwanmkwan/* * Whitespace encoding routines for the SNOW steganography program. * * Copyright (C) 1999 Matthew Kwan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * For license text, see https://spdx.org/licenses/Apache-2.0>. */ #include #include "snow.h" /* * Local variables used for encoding. */ static int encode_bit_count; static int encode_value; static char encode_buffer[BUFSIZ]; static BOOL encode_buffer_loaded; static int encode_buffer_length; static int encode_buffer_column; static BOOL encode_first_tab; static BOOL encode_needs_tab; static unsigned long encode_bits_used; static unsigned long encode_bits_available; static unsigned long encode_lines_extra; /* * Return the next tab position. */ static int tabpos ( int n ) { return ((n + 8) & ~7); } /* * Read a line of text, like fgets, but strip off trailing whitespace. */ static char * wsgets ( char *buf, int size, FILE *fp ) { int n; if (fgets (buf, BUFSIZ, fp) == NULL) return (NULL); n = strlen (buf) - 1; while (n >= 0 && (buf[n] == ' ' || buf[n] == '\t' || buf[n] == '\n' || buf[n] == '\r')) { buf[n] = '\0'; n--; } return (buf); } /* * Write a line of text, adding a newline. * Return FALSE if the write fails. */ static BOOL wsputs ( char *buf, FILE *fp ) { int len = strlen (buf); buf[len++] = '\n'; if (fwrite (buf, sizeof (char), len, fp) != len) { perror ("Text output"); return (FALSE); } return (TRUE); } /* * Calculate, approximately, how many bits can be stored in the line. */ static void whitespace_storage ( const char *buf, unsigned long *n_lo, unsigned long *n_hi ) { int n, len = strlen (buf); if (len > line_length - 2) return; if (len / 8 == line_length / 8) { *n_hi += 3; return; } if ((len & 7) > 0) { *n_hi += 3; len = tabpos (len); } if ((line_length & 7) > 0) *n_hi += 3; n = ((line_length - len) / 8) * 3; *n_hi += n; *n_lo += n; } /* * Load the encode buffer. * If there is no text to read, make it empty. */ static void encode_buffer_load ( FILE *fp ) { int i; if (wsgets (encode_buffer, BUFSIZ, fp) == NULL) { encode_buffer[0] = '\0'; encode_lines_extra++; } encode_buffer_length = strlen (encode_buffer); encode_buffer_column = 0; for (i=0; encode_buffer[i] != '\0'; i++) if (encode_buffer[i] == '\t') encode_buffer_column = tabpos (encode_buffer_column); else encode_buffer_column++; encode_buffer_loaded = TRUE; encode_needs_tab = FALSE; } /* * Append whitespace to the loaded buffer, if there is room. */ static BOOL encode_append_whitespace ( int nsp ) { int col = encode_buffer_column; if (encode_needs_tab) col = tabpos (col); if (nsp == 0) col = tabpos (col); else col += nsp; if (col >= line_length) return (FALSE); if (encode_needs_tab) { encode_buffer[encode_buffer_length++] = '\t'; encode_buffer_column = tabpos (encode_buffer_column); } if (nsp == 0) { encode_buffer[encode_buffer_length++] = '\t'; encode_buffer_column = tabpos (encode_buffer_column); encode_needs_tab = FALSE; } else { int i; for (i=0; i= line_length) { if (!wsputs (encode_buffer, outf)) return (FALSE); encode_buffer_load (inf); } encode_buffer[encode_buffer_length++] = '\t'; encode_buffer[encode_buffer_length] = '\0'; encode_buffer_column = tabpos (encode_buffer_column); encode_first_tab = TRUE; } /* Reverse the bit ordering */ nspc = ((val & 1) << 2) | (val & 2) | ((val & 4) >> 2); while (!encode_append_whitespace (nspc)) { if (!wsputs (encode_buffer, outf)) return (FALSE); encode_buffer_load (inf); } if (encode_lines_extra == 0) encode_bits_available += 3; return (TRUE); } /* * Flush the rest of the text to the output. */ static BOOL encode_write_flush ( FILE *inf, FILE *outf ) { char buf[BUFSIZ]; unsigned long n_lo = 0, n_hi = 0; if (encode_buffer_loaded) { if (!wsputs (encode_buffer, outf)) return (FALSE); encode_buffer_loaded = FALSE; encode_buffer_length = 0; encode_buffer_column = 0; } while (wsgets (buf, BUFSIZ, inf) != NULL) { whitespace_storage (buf, &n_lo, &n_hi); if (!wsputs (buf, outf)) return (FALSE); } encode_bits_available += (n_lo + n_hi) / 2; return (TRUE); } /* * Initialize the encoding routines. */ void encode_init (void) { encode_bit_count = 0; encode_value = 0; encode_buffer_loaded = FALSE; encode_buffer_length = 0; encode_buffer_column = 0; encode_first_tab = FALSE; encode_bits_used = 0; encode_bits_available = 0; encode_lines_extra = 0; } /* * Encode a single bit. */ BOOL encode_bit ( int bit, FILE *inf, FILE *outf ) { encode_value = (encode_value << 1) | bit; encode_bits_used++; if (++encode_bit_count == 3) { if (!encode_write_value (encode_value, inf, outf)) return (FALSE); encode_value = 0; encode_bit_count = 0; } return (TRUE); } /* * Flush the contents of the encoding routines. */ BOOL encode_flush ( FILE *inf, FILE *outf ) { if (encode_bit_count > 0) { while (encode_bit_count < 3) { /* Pad to 3 bits */ encode_value <<= 1; encode_bit_count++; } if (!encode_write_value (encode_value, inf, outf)) return (FALSE); } if (!encode_write_flush (inf, outf)) return (FALSE); if (!quiet_flag) { if (encode_lines_extra > 0) { fprintf (stderr, "Message exceeded available space by approximately %.2f%%.\n", ((double) encode_bits_used / encode_bits_available - 1.0) * 100.0); fprintf (stderr, "An extra %ld lines were added.\n", encode_lines_extra); } else { fprintf (stderr, "Message used approximately %.2f%% of available space.\n", (double) encode_bits_used / encode_bits_available * 100.0); } } return (TRUE); } /* * Decode the space count into actual bits. */ static BOOL decode_bits ( int spc, FILE *outf ) { int b1 = 0, b2 = 0, b3 = 0; if (spc > 7) { fprintf (stderr, "Illegal encoding of %d spaces\n", spc); return (FALSE); } if ((spc & 1) != 0) b1 = 1; if ((spc & 2) != 0) b2 = 1; if ((spc & 4) != 0) b3 = 1; if (!decrypt_bit (b1, outf)) return (FALSE); if (!decrypt_bit (b2, outf)) return (FALSE); if (!decrypt_bit (b3, outf)) return (FALSE); return (TRUE); } /* * Decode the whitespace contained in the string. */ static BOOL decode_whitespace ( const char *s, FILE *outf ) { int spc = 0; for (;; s++) { if (*s == ' ') { spc++; } else if (*s == '\t') { if (!decode_bits (spc, outf)) return (FALSE); spc = 0; } else if (*s == '\0') { if (spc > 0 && !decode_bits (spc, outf)) return (FALSE); return (TRUE); } } } /* * Extract a message from the input stream. */ BOOL message_extract ( FILE *inf, FILE *outf ) { char buf[BUFSIZ]; BOOL start_tab_found = FALSE; decrypt_init (); while (fgets (buf, BUFSIZ, inf) != NULL) { char *s, *last_ws = NULL; for (s = buf; *s != '\0' && *s != '\n' && *s != '\r'; s++) { if (*s != ' ' && *s != '\t') last_ws = NULL; else if (last_ws == NULL) last_ws = s; } if (*s == '\n' || *s == '\r') *s = '\0'; if (last_ws == NULL) continue; if (!start_tab_found && *last_ws == ' ') continue; if (!start_tab_found && *last_ws == '\t') { start_tab_found = TRUE; last_ws++; if (*last_ws == '\0') continue; } if (!decode_whitespace (last_ws, outf)) return (FALSE); } return (decrypt_flush (outf)); } /* * Calculate the amount of covert information that can be stored * in the file. */ void space_calculate ( FILE *fp ) { unsigned long n_lo = 0, n_hi = 0; char buf[BUFSIZ]; while (wsgets (buf, BUFSIZ, fp) != NULL) whitespace_storage (buf, &n_lo, &n_hi); if (n_lo > 0) { /* Allow for initial tab */ n_lo--; n_hi--; } if (n_lo == n_hi) { printf ("File has storage capacity of %ld bits (%ld bytes)\n", n_lo, n_lo / 8); } else { printf ("File has storage capacity of between %ld and %ld bits.\n", n_lo, n_hi); printf ("Approximately %ld bytes.\n", (n_lo + n_hi) / 16); } } snow-20130616/ice.h0000644000076400007640000000216212157331202012676 0ustar mkwanmkwan/* * Header file for the ICE encryption library. * * Copyright (C) 1999 Matthew Kwan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * For license text, see https://spdx.org/licenses/Apache-2.0>. */ #ifndef _ICE_H #define _ICE_H typedef struct ice_key_struct ICE_KEY; #if __STDC__ #define P_(x) x #else #define P_(x) () #endif extern ICE_KEY *ice_key_create P_((int n)); extern void ice_key_destroy P_((ICE_KEY *ik)); extern void ice_key_set P_((ICE_KEY *ik, const unsigned char *k)); extern void ice_key_encrypt P_((const ICE_KEY *ik, const unsigned char *ptxt, unsigned char *ctxt)); extern void ice_key_decrypt P_((const ICE_KEY *ik, const unsigned char *ctxt, unsigned char *ptxt)); #undef P_ #endif snow-20130616/README0000644000076400007640000000003212157312201012635 0ustar mkwanmkwanLicensed under Apache 2.0 snow-20130616/snow.h0000644000076400007640000000337312157331202013131 0ustar mkwanmkwan/* * Header file for the SNOW steganography program. * * Copyright (C) 1999 Matthew Kwan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * For license text, see https://spdx.org/licenses/Apache-2.0>. */ #ifndef _SNOW_H #define _SNOW_H #include /* * Define boolean types. */ typedef int BOOL; #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif /* * Define global variables. */ extern BOOL compress_flag; extern BOOL quiet_flag; extern int line_length; /* * Define external functions. */ extern void password_set (const char *passwd); extern BOOL message_extract (FILE *inf, FILE *outf); extern void space_calculate (FILE *inf); extern void compress_init (void); extern BOOL compress_bit (int bit, FILE *inf, FILE *outf); extern BOOL compress_flush (FILE *inf, FILE *outf); extern void uncompress_init (void); extern BOOL uncompress_bit (int bit, FILE *outf); extern BOOL uncompress_flush (FILE *outf); extern void encrypt_init (void); extern BOOL encrypt_bit (int bit, FILE *inf, FILE *outf); extern BOOL encrypt_flush (FILE *inf, FILE *outf); extern void decrypt_init (void); extern BOOL decrypt_bit (int bit, FILE *outf); extern BOOL decrypt_flush (FILE *outf); extern void encode_init (void); extern BOOL encode_bit (int bit, FILE *inf, FILE *outf); extern BOOL encode_flush (FILE *inf, FILE *outf); #endif snow-20130616/AUTHORS0000644000076400007640000000004512157312147013042 0ustar mkwanmkwanMatthew Kwan snow-20130616/main.c0000644000076400007640000001402412160521470013057 0ustar mkwanmkwan/* * COPYRIGHT AND LICENSE * * Copyright (C) 1999 Matthew Kwan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * For license text, see https://spdx.org/licenses/Apache-2.0>. * * DESCRIPTION * * Command-line program for hiding and extracting messages within * the whitespace of text files. * * Usage: snow [-C][-Q][-S][-p passwd][-l line-len] [-f file | -m message] * [infile [outfile]] * * -C : Use compression * -Q : Be quiet * -S : Calculate the space available in the file * -l : Maximum line length allowable * -p : Specify the password to encrypt the message * * -f : Insert the message contained in the file * -m : Insert the message given * * If the program is executed without either of the -f or -m options * then the program will attempt to extract a concealed message. * The output will go to outfile if specified, stdout otherwise. */ #include "snow.h" /* * Declaration of global variables. */ BOOL compress_flag = FALSE; BOOL quiet_flag = FALSE; int line_length = 80; /* * Encode a single character. */ static BOOL character_encode ( unsigned char c, FILE *infile, FILE *outfile ) { int i; for (i=0; i<8; i++) { int bit = ((c & (128 >> i)) != 0) ? 1 : 0; if (!compress_bit (bit, infile, outfile)) return (FALSE); } return (TRUE); } /* * Encode a string of characters. */ static BOOL message_string_encode ( const char *msg, FILE *infile, FILE *outfile ) { compress_init (); while (*msg != '\0') { if (!character_encode (*msg, infile, outfile)) return (FALSE); msg++; } return (compress_flush (infile, outfile)); } /* * Encode the contents of a file. */ static BOOL message_fp_encode ( FILE *msg_fp, FILE *infile, FILE *outfile ) { int c; compress_init (); while ((c = fgetc (msg_fp)) != EOF) if (!character_encode (c, infile, outfile)) return (FALSE); if (ferror (msg_fp) != 0) { perror ("Message file"); return (FALSE); } return (compress_flush (infile, outfile)); } /* * Display usage. */ static void showUsage ( const char *argv0 ) { printf ("Usage: %s [-C] [-Q] [-S] [-V | --version] [-h | --help]\n", argv0); printf ("\t[-p passwd] [-l line-len] [-f file | -m message]\n"); printf ("\t[infile [outfile]]\n"); } /* * Display version info. */ static void showVersion () { printf ( "20130616 Apache-2.0 Copyright (C) Matthew Kwan \n"); } /* * Program's starting point. * Processes command-line args and starts things running. */ int main ( int argc, char *argv[] ) { int c; int optind; BOOL errflag = FALSE; BOOL space_flag = FALSE; char *passwd = NULL; char *message_string = NULL; FILE *message_fp = NULL; FILE *infile = stdin; FILE *outfile = stdout; optind = 1; for (optind = 1; optind < argc #ifdef unix && argv[optind][0] == '-'; #else && (argv[optind][0] == '-' || argv[optind][0] == '/'); #endif optind++) { char c = argv[optind][1]; char *optarg; if (strcmp (argv[optind], "--help") == 0) { showUsage (argv[0]); return 0; } else if (strcmp (argv[optind], "--version") == 0) { showVersion (); return 0; } switch (c) { case 'C': compress_flag = TRUE; break; case 'Q': quiet_flag = TRUE; break; case 'S': space_flag = TRUE; break; case 'V': showVersion (); return 0; case 'f': if (argv[optind][2] != '\0') optarg = &argv[optind][2]; else if (++optind == argc) { errflag = TRUE; break; } else optarg = argv[optind]; if ((message_fp = fopen (optarg, "r")) == NULL) { perror (optarg); errflag = TRUE; } break; case 'h': showUsage (argv[0]); return 0; case 'l': if (argv[optind][2] != '\0') optarg = &argv[optind][2]; else if (++optind == argc) { errflag = TRUE; break; } else optarg = argv[optind]; if (sscanf (optarg, "%d", &line_length) != 1 || line_length < 8) { fprintf (stderr, "Illegal line length value '%s'\n", optarg); errflag = TRUE; } break; case 'm': if (argv[optind][2] != '\0') optarg = &argv[optind][2]; else if (++optind == argc) { errflag = TRUE; break; } else optarg = argv[optind]; message_string = optarg; break; case 'p': if (argv[optind][2] != '\0') optarg = &argv[optind][2]; else if (++optind == argc) { errflag = TRUE; break; } else optarg = argv[optind]; passwd = optarg; break; default: fprintf (stderr, "Illegal option '%s'\n", argv[optind]); errflag = TRUE; break; } if (errflag) break; } if (message_string != NULL && message_fp != NULL) { fprintf (stderr, "Cannot specify both message string and file\n"); errflag = TRUE; } if (errflag || optind < argc - 2) { showUsage (argv[0]); return 1; } if (passwd != NULL) password_set (passwd); if (optind < argc) { if ((infile = fopen (argv[optind], "r")) == NULL) { perror (argv[optind]); return 1; } } if (optind + 1 < argc) { if ((outfile = fopen (argv[optind + 1], "w")) == NULL) { perror (argv[optind + 1]); return 1; } } if (space_flag) { space_calculate (infile); } else if (message_string != NULL) { if (!message_string_encode (message_string, infile, outfile)) return 1; } else if (message_fp != NULL) { if (!message_fp_encode (message_fp, infile, outfile)) return 1; fclose (message_fp); } else { if (!message_extract (infile, outfile)) return 1; } if (outfile != stdout) fclose (outfile); if (infile != stdout) fclose (infile); return 0; } snow-20130616/encrypt.c0000644000076400007640000000723712157331202013625 0ustar mkwanmkwan/* * Encryption routines for the SNOW steganography program. * Uses the ICE encryption algorithm in 1-bit cipher-feedback (CFB) mode. * * Copyright (C) 1999 Matthew Kwan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * For license text, see https://spdx.org/licenses/Apache-2.0>. */ #include #include "snow.h" #include "ice.h" /* * The key to use for encryption/decryption. */ static ICE_KEY *ice_key = NULL; static unsigned char encrypt_iv_block[8]; /* * Build the ICE key from the supplied password. * Only uses the lower 7 bits from each character. */ void password_set ( const char *passwd ) { int i, level; unsigned char buf[1024]; level = (strlen (passwd) * 7 + 63) / 64; if (level == 0) { if (!quiet_flag) fprintf (stderr, "Warning: an empty password is being used\n"); level = 1; } else if (level > 128) { if (!quiet_flag) fprintf (stderr, "Warning: password truncated to 1170 chars\n"); level = 128; } if ((ice_key = ice_key_create (level)) == NULL) { if (!quiet_flag) fprintf (stderr, "Warning: failed to set password\n"); return; } for (i=0; i<1024; i++) buf[i] = 0; i = 0; while (*passwd != '\0') { unsigned char c = *passwd & 0x7f; int idx = i / 8; int bit = i & 7; if (bit == 0) { buf[idx] = (c << 1); } else if (bit == 1) { buf[idx] |= c; } else { buf[idx] |= (c >> (bit - 1)); buf[idx + 1] = (c << (9 - bit)); } i += 7; passwd++; if (i > 8184) break; } ice_key_set (ice_key, buf); /* Set the initialization vector with the key * with itself. */ ice_key_encrypt (ice_key, buf, encrypt_iv_block); } /* * Initialize the encryption routines. */ void encrypt_init (void) { encode_init (); } /* * Encrypt a single bit. */ BOOL encrypt_bit ( int bit, FILE *inf, FILE *outf ) { int i; unsigned char buf[8]; if (ice_key == NULL) return (encode_bit (bit, inf, outf)); ice_key_encrypt (ice_key, encrypt_iv_block, buf); if ((buf[0] & 128) != 0) bit = !bit; /* Rotate the IV block one bit left */ for (i=0; i<8; i++) { encrypt_iv_block[i] <<= 1; if (i < 7 && (encrypt_iv_block[i+1] & 128) != 0) encrypt_iv_block[i] |= 1; } encrypt_iv_block[7] |= bit; return (encode_bit (bit, inf, outf)); } /* * Flush the contents of the encryption routines. */ BOOL encrypt_flush ( FILE *inf, FILE *outf ) { ice_key_destroy (ice_key); return (encode_flush (inf, outf)); } /* * Initialize the decryption routines. */ void decrypt_init (void) { uncompress_init (); } /* * Decrypt a single bit. */ BOOL decrypt_bit ( int bit, FILE *outf ) { int i; int nbit; unsigned char buf[8]; if (ice_key == NULL) return (uncompress_bit (bit, outf)); ice_key_encrypt (ice_key, encrypt_iv_block, buf); if ((buf[0] & 128) != 0) nbit = !bit; else nbit = bit; /* Rotate the IV block one bit left */ for (i=0; i<8; i++) { encrypt_iv_block[i] <<= 1; if (i < 7 && (encrypt_iv_block[i+1] & 128) != 0) encrypt_iv_block[i] |= 1; } encrypt_iv_block[7] |= bit; return (uncompress_bit (nbit, outf)); } /* * Flush the contents of the decryption routines. */ BOOL decrypt_flush ( FILE *outf ) { ice_key_destroy (ice_key); return (uncompress_flush (outf)); } snow-20130616/ice.c0000644000076400007640000002003212157331202012665 0ustar mkwanmkwan/* * Implementation of the ICE encryption algorithm. * * Copyright (C) 1999 Matthew Kwan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * For license text, see https://spdx.org/licenses/Apache-2.0>. */ #include "ice.h" #include #include /* Structure of a single round subkey */ typedef unsigned long ICE_SUBKEY[3]; /* Internal structure of the ICE_KEY structure */ struct ice_key_struct { int ik_size; int ik_rounds; ICE_SUBKEY *ik_keysched; }; /* The S-boxes */ static unsigned long ice_sbox[4][1024]; static int ice_sboxes_initialised = 0; /* Modulo values for the S-boxes */ static const int ice_smod[4][4] = { {333, 313, 505, 369}, {379, 375, 319, 391}, {361, 445, 451, 397}, {397, 425, 395, 505}}; /* XOR values for the S-boxes */ static const int ice_sxor[4][4] = { {0x83, 0x85, 0x9b, 0xcd}, {0xcc, 0xa7, 0xad, 0x41}, {0x4b, 0x2e, 0xd4, 0x33}, {0xea, 0xcb, 0x2e, 0x04}}; /* Expanded permutation values for the P-box */ static const unsigned long ice_pbox[32] = { 0x00000001, 0x00000080, 0x00000400, 0x00002000, 0x00080000, 0x00200000, 0x01000000, 0x40000000, 0x00000008, 0x00000020, 0x00000100, 0x00004000, 0x00010000, 0x00800000, 0x04000000, 0x20000000, 0x00000004, 0x00000010, 0x00000200, 0x00008000, 0x00020000, 0x00400000, 0x08000000, 0x10000000, 0x00000002, 0x00000040, 0x00000800, 0x00001000, 0x00040000, 0x00100000, 0x02000000, 0x80000000}; /* The key rotation schedule */ static const int ice_keyrot[16] = { 0, 1, 2, 3, 2, 1, 3, 0, 1, 3, 2, 0, 3, 1, 0, 2}; /* * Galois Field multiplication of a by b, modulo m. * Just like arithmetic multiplication, except that additions and * subtractions are replaced by XOR. */ static unsigned int gf_mult ( register unsigned int a, register unsigned int b, register unsigned int m ) { register unsigned int res = 0; while (b) { if (b & 1) res ^= a; a <<= 1; b >>= 1; if (a >= 256) a ^= m; } return (res); } /* * Galois Field exponentiation. * Raise the base to the power of 7, modulo m. */ static unsigned long gf_exp7 ( register unsigned int b, unsigned int m ) { register unsigned int x; if (b == 0) return (0); x = gf_mult (b, b, m); x = gf_mult (b, x, m); x = gf_mult (x, x, m); return (gf_mult (b, x, m)); } /* * Carry out the ICE 32-bit P-box permutation. */ static unsigned long ice_perm32 ( register unsigned long x ) { register unsigned long res = 0; register const unsigned long *pbox = ice_pbox; while (x) { if (x & 1) res |= *pbox; pbox++; x >>= 1; } return (res); } /* * Initialise the ICE S-boxes. * This only has to be done once. */ static void ice_sboxes_init (void) { register int i; for (i=0; i<1024; i++) { int col = (i >> 1) & 0xff; int row = (i & 0x1) | ((i & 0x200) >> 8); unsigned long x; x = gf_exp7 (col ^ ice_sxor[0][row], ice_smod[0][row]) << 24; ice_sbox[0][i] = ice_perm32 (x); x = gf_exp7 (col ^ ice_sxor[1][row], ice_smod[1][row]) << 16; ice_sbox[1][i] = ice_perm32 (x); x = gf_exp7 (col ^ ice_sxor[2][row], ice_smod[2][row]) << 8; ice_sbox[2][i] = ice_perm32 (x); x = gf_exp7 (col ^ ice_sxor[3][row], ice_smod[3][row]); ice_sbox[3][i] = ice_perm32 (x); } } /* * Create a new ICE key. */ ICE_KEY * ice_key_create ( int n ) { ICE_KEY *ik; if (!ice_sboxes_initialised) { ice_sboxes_init (); ice_sboxes_initialised = 1; } if ((ik = (ICE_KEY *) malloc (sizeof (ICE_KEY))) == NULL) return (NULL); if (n < 1) { ik->ik_size = 1; ik->ik_rounds = 8; } else { ik->ik_size = n; ik->ik_rounds = n * 16; } if ((ik->ik_keysched = (ICE_SUBKEY *) malloc (ik->ik_rounds * sizeof (ICE_SUBKEY))) == NULL) { free (ik); return (NULL); } return (ik); } /* * Destroy an ICE key. * Zero out the memory to prevent snooping. */ void ice_key_destroy ( ICE_KEY *ik ) { int i, j; if (ik == NULL) return; for (i=0; iik_rounds; i++) for (j=0; j<3; j++) ik->ik_keysched[i][j] = 0; ik->ik_rounds = ik->ik_size = 0; if (ik->ik_keysched != NULL) free (ik->ik_keysched); free (ik); } /* * The single round ICE f function. */ static unsigned long ice_f ( register unsigned long p, const ICE_SUBKEY sk ) { unsigned long tl, tr; /* Expanded 40-bit values */ unsigned long al, ar; /* Salted expanded 40-bit values */ /* Left half expansion */ tl = ((p >> 16) & 0x3ff) | (((p >> 14) | (p << 18)) & 0xffc00); /* Right half expansion */ tr = (p & 0x3ff) | ((p << 2) & 0xffc00); /* Perform the salt permutation */ /* al = (tr & sk[2]) | (tl & ~sk[2]); */ /* ar = (tl & sk[2]) | (tr & ~sk[2]); */ al = sk[2] & (tl ^ tr); ar = al ^ tr; al ^= tl; al ^= sk[0]; /* XOR with the subkey */ ar ^= sk[1]; /* S-box lookup and permutation */ return (ice_sbox[0][al >> 10] | ice_sbox[1][al & 0x3ff] | ice_sbox[2][ar >> 10] | ice_sbox[3][ar & 0x3ff]); } /* * Encrypt a block of 8 bytes of data with the given ICE key. */ void ice_key_encrypt ( const ICE_KEY *ik, const unsigned char *ptext, unsigned char *ctext ) { register int i; register unsigned long l, r; l = (((unsigned long) ptext[0]) << 24) | (((unsigned long) ptext[1]) << 16) | (((unsigned long) ptext[2]) << 8) | ptext[3]; r = (((unsigned long) ptext[4]) << 24) | (((unsigned long) ptext[5]) << 16) | (((unsigned long) ptext[6]) << 8) | ptext[7]; for (i = 0; i < ik->ik_rounds; i += 2) { l ^= ice_f (r, ik->ik_keysched[i]); r ^= ice_f (l, ik->ik_keysched[i + 1]); } for (i = 0; i < 4; i++) { ctext[3 - i] = r & 0xff; ctext[7 - i] = l & 0xff; r >>= 8; l >>= 8; } } /* * Decrypt a block of 8 bytes of data with the given ICE key. */ void ice_key_decrypt ( const ICE_KEY *ik, const unsigned char *ctext, unsigned char *ptext ) { register int i; register unsigned long l, r; l = (((unsigned long) ctext[0]) << 24) | (((unsigned long) ctext[1]) << 16) | (((unsigned long) ctext[2]) << 8) | ctext[3]; r = (((unsigned long) ctext[4]) << 24) | (((unsigned long) ctext[5]) << 16) | (((unsigned long) ctext[6]) << 8) | ctext[7]; for (i = ik->ik_rounds - 1; i > 0; i -= 2) { l ^= ice_f (r, ik->ik_keysched[i]); r ^= ice_f (l, ik->ik_keysched[i - 1]); } for (i = 0; i < 4; i++) { ptext[3 - i] = r & 0xff; ptext[7 - i] = l & 0xff; r >>= 8; l >>= 8; } } /* * Set 8 rounds [n, n+7] of the key schedule of an ICE key. */ static void ice_key_sched_build ( ICE_KEY *ik, unsigned short *kb, int n, const int *keyrot ) { int i; for (i=0; i<8; i++) { register int j; register int kr = keyrot[i]; ICE_SUBKEY *isk = &ik->ik_keysched[n + i]; for (j=0; j<3; j++) (*isk)[j] = 0; for (j=0; j<15; j++) { register int k; unsigned long *curr_sk = &(*isk)[j % 3]; for (k=0; k<4; k++) { unsigned short *curr_kb = &kb[(kr + k) & 3]; register int bit = *curr_kb & 1; *curr_sk = (*curr_sk << 1) | bit; *curr_kb = (*curr_kb >> 1) | ((bit ^ 1) << 15); } } } } /* * Set the key schedule of an ICE key. */ void ice_key_set ( ICE_KEY *ik, const unsigned char *key ) { int i; if (ik->ik_rounds == 8) { unsigned short kb[4]; for (i=0; i<4; i++) kb[3 - i] = (key[i*2] << 8) | key[i*2 + 1]; ice_key_sched_build (ik, kb, 0, ice_keyrot); return; } for (i = 0; i < ik->ik_size; i++) { int j; unsigned short kb[4]; for (j=0; j<4; j++) kb[3 - j] = (key[i*8 + j*2] << 8) | key[i*8 + j*2 + 1]; ice_key_sched_build (ik, kb, i*8, ice_keyrot); ice_key_sched_build (ik, kb, ik->ik_rounds - 8 - i*8, &ice_keyrot[8]); } } snow-20130616/snow.10000644000076400007640000001017012162301755013041 0ustar mkwanmkwan.TH SNOW 1 "28 Dec 1996" "Version 1.1" .SH NAME snow \- whitespace steganography program .SH SYNOPSIS .B snow [ .B -CQS ] [ .B -h | .B --help ] [ .B -V | .B --version ] [ .B -p .I passwd ] [ .B -l .I line-len ] [ .B -f .I file | .B -m .I message ] [ .I infile [ .I outfile ]] .SH DESCRIPTION \fBsnow\fP is a program for concealing messages in text files by appending tabs and spaces on the end of lines, and for extracting messages from files containing hidden messages. Tabs and spaces are invisible to most text viewers, hence the steganographic nature of this encoding scheme. .PP The data is concealed in the text file by appending sequences of up to 7 spaces, interspersed with tabs. This usually allows 3 bits to be stored every 8 columns. An alternative encoding scheme, using alternating spaces and tabs to represent zeroes and ones, was rejected because, although it used fewer bytes, it required more columns per bit (4.5 vs 2.67). .PP The start of the data is indicated by an appended tab character, which allows the insertion of mail and news headers without corrupting the data. .PP \fBsnow\fP provides rudimentary compression, using Huffman tables optimised for English text. However, if the data is not text, or if there is a lot of data, the use of the built-in compression is not recommended, since an external compression program such as \fBcompress\fP or \fBgzip\fP will do a much better job. .PP Encryption is also provided, using the ICE encryption algorithm in 1-bit cipher-feedback (CFB) mode. Because of ICE's arbitrary key size, passwords of any length up to 1170 characters are supported (since only 7 bits of each character are used, keys up to 1024-bytes are supported). .PP If a message string or message file are specified on the command-line, \fBsnow\fP will attempt to conceal the message in the file \fIinfile\fP if specified, or standard input otherwise. The resulting file will be written to \fIoutfile\fP if specified, or standard output if not. .PP If no message string is provided, \fBsnow\fP attempts to extract a message from the input file. The result is written to the output file or standard output. .SH OPTIONS .TP .B -C Compress the data if concealing, or uncompress it if extracting. .TP \fB-f\fP \fImessage-file\fP The contents of this file will be concealed in the input text file. .TP \fB-l\fP \fIline-len\fP When appending whitespace, \fBsnow\fP will always produce lines shorter than this value. By default it is set to 80. .TP \fB-m\fP \fImessage-string\fP The contents of this string will be concealed in the input text file. Note that, unless a newline is somehow included in the string, a newline will not be printed when the message is extracted. .TP \fB-p\fP \fIpassword\fP If this is set, the data will be encrypted with this password during concealment, or decrypted during extraction. .TP .B -Q Quiet mode. If not set, the program reports statistics such as compression percentages and amount of available storage space used. .TP .B -S Report on the approximate amount of space available for hidden message in the text file. Line length is taken into account, but other options are ignored. .TP .B -V, --version Display usage information and exit. .TP .B -h, --help Display usage information and exit. .SH EXAMPLES The following command will conceal the message "I am lying" in the file \fIinfile\fP, with compression, and encrypted with the password "hello world". The resulting text will be stored in \fIoutfile\fP. .PP .RS \fBsnow \-C \-m "I am lying" \-p "hello world" infile outfile\fP .RE .PP To extract the message, the command would be .PP .RS \fBsnow \-C \-p "hello world" outfile\fP .RE .PP Note that the resulting message will not be terminated by a newline. .PP To prevent line wrap if text with concealed whitespace is likely to be indented by mail or news readers, a line length of 72 or less can be used. .PP .RS \fBsnow \-C \-l 72 \-m "I am lying" infile outfile\fP .RE .PP The approximate storage capacity of a file can be determined with the \fB-S\fP option. .PP .RS \fBsnow \-S \-l 72 infile\fP .RE .SH AUTHOR This application was written by Matthew Kwan, who can be reached at mkwan@darkside.com.au .SH SEE ALSO \fBice_key_create\fP(3)