Lecture 24 LCG Cipher

Joseph Haugh

University of New Mexico

Free Recall

Review Question 1

What is the output of the following snippet of code?

int x = 10, y = 20;
int *ptr = &x;
*ptr += 5;
ptr = &y;
*ptr *= 2;
printf("%d %d\n", x, y);
15 40

Review Question 2

What is the output of the following snippet of code?

char str[] = "Hello, world!";
char *ptr = str;
while (*ptr != '\0') {
    if (*ptr == 'o') *ptr = 'O';
    ptr++;
}
printf("%s\n", str);
HellO, wOrld!

Review Question 3

What is the output of the following snippet of code?

int arr[] = {1, 2, 3, 4, 5};
int *ptr = arr;
int sum = 0;
for (int i = 0; i < 5; i++) {
    sum += *(ptr + i);
}
printf("sum: %d\n", sum);
sum: 15

Review Question 4

What is the output of the following snippet of code?

int x = 5;
int *ptr1 = &x;
int **ptr2 = &ptr1;
**ptr2 = 10;
printf("%d\n", x);
10

Cipher

  • In cryptography, a cipher (or cypher) is an algorithm for performing encryption or decryption.
  • When using a cipher, the original information is known as plaintext, and the encrypted form as ciphertext.
  • The encrypting procedure of the cipher usually depends on a piece of auxiliary information, called a key.
  • A key must be selected before using a cipher to encrypt a message.
  • Without knowledge of the key, it should be difficult, if not nearly impossible, to decrypt the resulting ciphertext into readable plaintext.

Substitution Cipher

  • In cryptography, a substitution cipher is a method of encryption by which units of plaintext are replaced with ciphertext according to a regular system.
  • Example: case insensitive substitution cipher using a shifted alphabet with keyword “zebras”:
    • Plaintext alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ
    • Ciphertext alphabet: ZEBRASCDFGHIJKLMNOPQTUVWXY

flee at once. we are discovered!

Enciphers to

SIAA ZQ LKBA. VA ZOA RFPBLUAOAR!

Other substitution ciphers

Caesar cipher
Shift alphabet by fixed amount. (Caesar apparently used 3.)
ROT13
Replace letters with those 13 away. Used to hide spoilers on newsgroups.
pigpen cipher
Replace letters with symbols.
Pigpen cipher key

Substitution Cipher: Encipher Example

OENp(ENTE#X@EN#zNp(ENCL]pEnN7p-pE;8N]LN}
dnEdNp#Nz#duN-Nu#dENXEdzE9pNCL]#L8NE;p-b
@];(N0G;p]9E8N]L;GdENn#uE;p]9Nld-L/G]@]p
_8NXd#|]nENz#dNp(EN9#uu#LNnEzEL;E8NXd#u#
pENp(ENQELEd-@NOE@z-dE8N-LnN;E9GdENp(EN^
@E;;]LQ;N#zN<]bEdp_Np#N#Gd;E@|E;N-LnN#Gd
NT#;pEd]p_8Nn#N#dn-]LN-LnNE;p-b@];(Np(];
N5#L;p]pGp]#LNz#dNp(ENCL]pEnN7p-pE;N#zN)
uEd]9-D

Breaking a Substitution Cipher

In English,

  • The most common character is the space: .
  • Letters in order of frequency are: ETAONRISHDLFCMUGYPWBVKXJQZ
  • Letter pairs in order of frequency are: TH HE AN RE ER IN ON AT ND ST ES EN OF TE ED OR TI HI AS TO
  • Doubled letters in order of frequency are: LL EE SS OO TT FF RR NN PP CC MM

Substitution Cipher: plaintext & Map

We the People of the United States, in Order to form a more perfect Union, establish Justice, insure domestic Tranquility, provide for the common defense, promote the general Welfare, and secure the Blessings of Liberty to ourselves and our Posterity, do ordain and establish this Constitution for the United States of America.

 =51
e=39 
t=28
o=24
[ N] [!%] ["Z] [#1] [$f] [%=] [&r] ['I] [( ] [)U] [*,]
[+a] [,8] [-m] [.D] [/y] [0P] [1'] [2\] [33] [4h] [5?] 
[6t] [7K] [8"] [9W] [:.] [;c] [<:] [=o] [>F] [?{] [@R]
[A)] [B^] [C5] [Dj] [EA] [Fv] [GM] [H$] [IY] [J0] [Ke]
[L<] [Mq] [NH] [O}] [PT] [Q+] [R`] [S7] [Tl] [UC] [Vx]
[WO] [X&] [Y[] [Z2] [[g] [\>] []s] [^J] [_!] [`V] [a-]
[bb] [c9] [dn] [eE] [fz] [gQ] [h(] [i]] [j4] [ki] [l@]
[mu] [nL] [o#] [pX] [q/] [rd] [s;] [tp] [uG] [v|] [wS]
[x*] [y_] [z6] [{k] [|B] [}w]

Substitution Map Generator: Globals

#define ASCII_START 32
#define ASCII_END 126 
#define MAP_SIZE 94

char map[MAP_SIZE];
  • Program that creates a substitution map based on the first letter of the plaintext message.
  • The program creates a one-to-one map of all printable ASCII characters.

Substitution Map Generator: buildMap

void buildMap(char seed) { 
  int i; 
  int m = 94;
  int a = 189; 
  int c = 53;
  int n = seed;
 
  for (i = 0; i < MAP_SIZE; i++) {
    n = (a * n + c) % m;
    map[i] = n + ASCII_START;
  }
}
  • seed: first number in the pseudo-random sequence.
  • m, a, c: constants chosen to give pseudo-random behavior.
  • for loop body: generates a pseudo-random number between 0 and m, maps character i + ASCII_START to n + ASCII_START

Substitution Map Generator: printMap

void printMap() {
  int i;
  for (i = 0; i < MAP_SIZE; i++) {  
    printf("[%c%c] ", i + ASCII_START, map[i]);
 
    if ((i % 16) == 15) printf("\n");
  }
  printf("\n");
}

Substitution Map Generator: main

void main() { 
  char c = getchar();
  buildMap(c);  
  printMap();
  int i = 0;
  while (c != EOF) { 
    if (c < ASCII_START) break;
    if (c > ASCII_END) break; 
    if (i % 40 == 0) printf("\n");
    printf("%c", map[c - ASCII_START]);
    c = getchar();
    i++; 
  }
  printf("\n");
}

Book Cipher

A book cipher is a cipher in which the key is some aspect of a book or other piece of text.

A message is typically encoded by three numbers for each letter:

  • Page
  • Line
  • Word

Where the encoded letter is the first letter of the specified word.

It is typically essential that both correspondents not only have the same book, but the same edition.

One-time pad

  • Random key (or “pad”) is at least as long as the text.
  • Add plaintext to key (modulo 26) to encrypt.
  • Subtract key from ciphertext to decrypt.
  • Destroy the key after use.
  • Problems:
    • Truly random key is hard to produce
    • How to exchange the key securely?
    • Never ever use the key again.
  • Modern stream ciphers mimic the one-time pad.

Modern Cipher Categories

Stream Ciphers
Applied to a continuous stream of symbols. Algorithms applied to small blocks (1 to 16 bytes) are often still called stream ciphers.
Block Ciphers
Applied to blocks of symbols.
Symmetric Key Algorithms
The same key is used for both encryption and decryption. For example: RC4 (used in Secure Sockets Layer (SSL)).
Asymmetric Key Algorithms
A different key is used for both encryption and decryption. For example: RSA which uses public / private key pairs.

RSA: Key Generation

  1. Choose two distinct prime numbers p and q. The primes should be chosen uniformly at random and should be of similar bit-length.
  2. Compute the divisor, n = pq, to be used in the modulus operation.
  3. Compute ϕ(pq) = (p − 1)(q − 1). The totient, ϕ, of a positive integer n is defined to be the number of positive integers less than or equal to n that are coprime to n.
  4. Choose an integer e such that 1 < e < ϕ(pq), and e and ϕ(pq) are coprime.
  5. Find d: (ed − 1) can be evenly divided by ϕ(p − 1)(q − 1).
  6. The public key consists of the modulus n and e.
  7. The private key consists of the modulus n and d.

Linear Congruential Generator (LCG)

A Linear Congruential Generator is one of the oldest and best known pseudorandom number generator algorithms:

Xn + 1 = (aXn + c) mod  m

where Xn is the sequence of pseudorandom values, and

  • Modulus: m, 0 < m
  • Multiplier: a, 0 < a < m
  • Increment: c, 0 ≤ c < m
  • Seed: X0, 0 ≤ X0 < m

LCG example

Example:

Xn + 1 = (7Xn + 11) mod  18, X0 = 0.

X1 = (7(0) + 11) mod  18 = 11

X2 = (7(11) + 11) mod  18 = 16

X3 = (7(16) + 11) mod  18 = 15

X4 = (7(15) + 11) mod  18 = 8

LCG with Pseudorandom Behavior

Xn + 1 = (aXn + c) mod  m

  • All of the values, a, c, m, and Xn used in an LCG are integers.
  • The sequence of integers in an LCG can never have a period greater than m. Why?
  • Some values of the modulus, multiplier and increment yield a sequence with maximum period and with good pseudorandom behavior.

LCG with Pseudorandom Behavior

An LCG will have a full period if and only if:

  • c and m are coprime (have no common factor  > 1)
  • a − 1 is divisible by all prime factors of m,
  • a − 1 is a multiple of 4 if m is a multiple of 4.

LCGs in Common Use

Source m a c
Numerical Recipes 232 1664525 1013904223
Borland C/C++ 232 22695477 1
glibc (used by GCC) 231 1103515245 12345
ANSI C: Watcom, Digital Mars, CodeWarrior, IBM VisualAge C/C++ 231 1103515245 12345

Note: LCG’s do not always return all of the bits in the values they produce.
Example: Java produces 48 bits, but only returns the 32 most significant.

table from wikipedia

Linear Congruential Generator in C

void main () { 
  unsigned long m = 1 << 31;
  unsigned long a = 1103515245;
  unsigned long c = 12345;
  unsigned long x = 123456;
 
  int i;
  for (i = 1; i <= 100; i++) {
    x = (a * x + c) % m;  
    printf("%20lu\n", x);
  }
}
     136235578099065
15519887047211639486
13838650204930187039
 3346717808905085548
 3049859088482533429
 7398829542172257482
15952872801263783483
 9897407542008592728
12436645181455133361
 8967167257519066006
15551416184959193879
14392011937321128708
 7012146815830884589
  837494824685357858
 9089108537697995187
 4486637365379619696
10706175307392302825
 3333036225721595758
15798734497693109775
 1184521088365346460
  762097951296315557
14053214745497771130
13752776674615655467
 4036971838066272392
13168213029112046113
 2176075275402511942
11251131393832824839
 9338128740141843764
 7951965562090585949

Toy Linear Congruential Generator

void main () { 
  int m = 18;
  int a = 7;
  int c = 1;
  int x = 0;

  int i;
  for (i = 1; i <= 28; i++) {
    printf("%4d\n", x);
    x = (a * x + c) % m;
  }
}
   0
   1
   8
   3
   4
  11
   6
   7
  14
   9
  10
  17
  12
  13
   2
  15
  16
   5
   0
   1
   8
   3
   4
  11
   6
   7
  14
   9

Poor Linear Congruential Generator

void main() {
 int m = 18;
 int a = 6;
 int c = 1;
 int x = 0;
 
 int i;
 for (i = 1; i <= 14; i++)
 {
   printf("%4d\n", x);
   x = (a * x + c) % m;
 }
}

This LCG does NOT have a full period.

How can this be known before computing it?

(6 × 7 + 1) mod  18

(42 + 1) mod  18

43 mod  18

7

  0
  1
  7
  7
  7
  7
  7
  7
  7
  7
  7
  7
  7
  7

Question: Linear Congruential Generator

void main() {
  int m = 10;
  int a = 2;
  int c = 1;
  int x = 7;
 
  int i;
  for (i = 1; i <= 4; i++) {
    printf("%d ", x);
    x = (a * x + c) % m;
  }
  printf("\n");
}

The output is:

  1. 7 5 1 3
  2. 7 5 7 4
  3. 7 5 6 7
  4. 7 5 2 6
  5. 7 5 3 7

Question: Linear Congruential Generator

void main() {
  int m = 10;
  int a = 2;
  int c = 1;
  int x = 7;
 
  int i;
  for (i = 1; i <= 4; i++) {
    printf("%d ", x);
    x = (a * x + c) % m;
  }
  printf("\n");
}

The output is:

  1. 7 5 1 3