1 /* $NetBSD: caesar.c,v 1.22 2008/07/20 01:03:21 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Adams. 9 * 10 * Authors: 11 * Stan King, John Eldridge, based on algorithm suggested by 12 * Bob Morris 13 * 29-Sep-82 14 * Roland Illig, 2005 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41 #include <sys/cdefs.h> 42 #ifndef lint 43 __COPYRIGHT("@(#) Copyright (c) 1989, 1993\ 44 The Regents of the University of California. All rights reserved."); 45 #endif /* not lint */ 46 47 #ifndef lint 48 #if 0 49 static char sccsid[] = "@(#)caesar.c 8.1 (Berkeley) 5/31/93"; 50 #else 51 __RCSID("$NetBSD: caesar.c,v 1.22 2008/07/20 01:03:21 lukem Exp $"); 52 #endif 53 #endif /* not lint */ 54 55 #include <err.h> 56 #include <errno.h> 57 #include <limits.h> 58 #include <math.h> 59 #include <stdio.h> 60 #include <string.h> 61 #include <stdlib.h> 62 63 #define NCHARS (1 << CHAR_BIT) 64 #define LETTERS (26) 65 66 /* 67 * letter frequencies (taken from some unix(tm) documentation) 68 * (unix is a trademark of Bell Laboratories) 69 */ 70 static const unsigned char upper[LETTERS] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 71 static const unsigned char lower[LETTERS] = "abcdefghijklmnopqrstuvwxyz"; 72 static double stdf[LETTERS] = { 73 7.97, 1.35, 3.61, 4.78, 12.37, 2.01, 1.46, 4.49, 6.39, 0.04, 74 0.42, 3.81, 2.69, 5.92, 6.96, 2.91, 0.08, 6.63, 8.77, 9.68, 75 2.62, 0.81, 1.88, 0.23, 2.07, 0.06 76 }; 77 78 static unsigned char rottbl[NCHARS]; 79 80 81 static void 82 init_rottbl(int rot) 83 { 84 size_t i; 85 86 rot %= LETTERS; /* prevent integer overflow */ 87 88 for (i = 0; i < NCHARS; i++) 89 rottbl[i] = (unsigned char)i; 90 91 for (i = 0; i < LETTERS; i++) 92 rottbl[upper[i]] = upper[(i + rot) % LETTERS]; 93 94 for (i = 0; i < LETTERS; i++) 95 rottbl[lower[i]] = lower[(i + rot) % LETTERS]; 96 } 97 98 static void 99 print_file(void) 100 { 101 int ch; 102 103 while ((ch = getchar()) != EOF) { 104 if (putchar(rottbl[ch]) == EOF) { 105 err(EXIT_FAILURE, "<stdout>"); 106 /* NOTREACHED */ 107 } 108 } 109 } 110 111 static void 112 print_array(const unsigned char *a, size_t len) 113 { 114 size_t i; 115 116 for (i = 0; i < len; i++) { 117 if (putchar(rottbl[a[i]]) == EOF) { 118 err(EXIT_FAILURE, "<stdout>"); 119 /* NOTREACHED */ 120 } 121 } 122 } 123 124 static int 125 get_rotation(const char *arg) 126 { 127 long rot; 128 char *endp; 129 130 errno = 0; 131 rot = strtol(arg, &endp, 10); 132 if (errno == 0 && (arg[0] == '\0' || *endp != '\0')) 133 errno = EINVAL; 134 if (errno == 0 && (rot < 0 || rot > INT_MAX)) 135 errno = ERANGE; 136 if (errno) 137 err(EXIT_FAILURE, "Bad rotation value `%s'", arg); 138 return (int)rot; 139 } 140 141 static void 142 guess_and_rotate(void) 143 { 144 unsigned char inbuf[2048]; 145 unsigned int obs[NCHARS]; 146 size_t i, nread; 147 double dot, winnerdot; 148 int try, winner; 149 int ch; 150 151 /* adjust frequency table to weight low probs REAL low */ 152 for (i = 0; i < LETTERS; i++) 153 stdf[i] = log(stdf[i]) + log(LETTERS / 100.0); 154 155 /* zero out observation table */ 156 (void)memset(obs, 0, sizeof(obs)); 157 158 for (nread = 0; nread < sizeof(inbuf); nread++) { 159 if ((ch = getchar()) == EOF) 160 break; 161 inbuf[nread] = (unsigned char) ch; 162 } 163 164 for (i = 0; i < nread; i++) 165 obs[inbuf[i]]++; 166 167 /* 168 * now "dot" the freqs with the observed letter freqs 169 * and keep track of best fit 170 */ 171 winner = 0; 172 winnerdot = 0.0; 173 for (try = 0; try < LETTERS; try++) { 174 dot = 0.0; 175 for (i = 0; i < LETTERS; i++) 176 dot += (obs[upper[i]] + obs[lower[i]]) 177 * stdf[(i + try) % LETTERS]; 178 179 if (try == 0 || dot > winnerdot) { 180 /* got a new winner! */ 181 winner = try; 182 winnerdot = dot; 183 } 184 } 185 186 init_rottbl(winner); 187 print_array(inbuf, nread); 188 print_file(); 189 } 190 191 int 192 main(int argc, char **argv) 193 { 194 195 if (argc == 1) { 196 guess_and_rotate(); 197 } else if (argc == 2) { 198 init_rottbl(get_rotation(argv[1])); 199 print_file(); 200 } else { 201 (void)fprintf(stderr, "usage: caesar [rotation]\n"); 202 exit(EXIT_FAILURE); 203 /* NOTREACHED */ 204 } 205 206 if (ferror(stdin)) { 207 errx(EXIT_FAILURE, "<stdin>"); 208 /* NOTREACHED */ 209 } 210 211 (void)fflush(stdout); 212 if (ferror(stdout)) { 213 errx(EXIT_FAILURE, "<stdout>"); 214 /* NOTREACHED */ 215 } 216 217 return 0; 218 } 219