Main Tenets of InfoSec
From NCyTE
- Confidentiality
- Integrity
- Availability
- Authenticity – How do we know where it came from
- Non-repudiation
Dr. Greg Bernstein
February 15th, 2021
NCyTE: Applied Cryptography Module
Crypto101, for programmers, Python Cryptography Package for getting things done safely
GnuPG – Gnu Privacy Guard, GPG4Win – Gnu Privacy Guard for Windows
Cryptography: An Introduction(3rd Edition), Nigel Smart, free PDF from author, aimed at a rigorous undergraduate math course, 436 pages.
An Introduction to Cryptography, Mohamed Barakat, Christian Eder, Timo Hanke, 2018, free PDF from authors, rigorous mathematical approach, 145 pages
From NCyTE
Students will be able to define encryption, decryption, plaintext, ciphertext, and encryption/decryption key, and explain their use in cryptography.
Students will be able to describe attack scenarios against an encryption algorithm.
Students will be able to use early cipher methods such as a Caesar cipher or substitution cipher to encrypt/decrypt data “by hand”.
From NCyTE
Students will be able to identify commonly used algorithms for symmetric encryption.
Students will be able to explain the challenge of key distribution in symmetric key encryption.
From NCyTE
From NCyTE
Cryptography is “the practice and study of techniques for secure communication in the presence of adversaries” (Wikipedia)
It is the science of designing systems to store and transmit data in a secure way so that it preserves its integrity and is accessible to only those with proper authentication and authorization.
From NCyTE
From NCyTE
Cryptanalysis: breaking cryptographic systems
Cryptography
From NCyTE
Map each letter to a letter further in the alphabet by a fixed amount
Rotate a string or list of characters
alphaUpper = "ABCDEFGHIJKLMONPQRSTUVWXYZ"
def rotate(n, alist):
""" Rotates a list/string by the integer n (less than the list length).
Use this in the creation of Caesar/shift ciphers
"""
return alist[n:] + alist[:n] # Python list slice trick
print(rotate(4, alphaUpper)) # try it
Create a character “map” based on rotated string
def createCMap(permList):
"""Creates a cipher map for simple encryption.
The permList is a permuted string/list of uppercase letters.
Returns a dictionary that can be used to map characters
"""
mapDict = {}
for i, v in enumerate(alphaUpper):
mapDict[v] = permList[i]
return mapDict
cMapRot3 = createCMap(rotate(3, alphaUpper)) # try it
print(cMapRot3)
exLetter = "G"
print(f"The letter {exLetter} gets transformed into {cMapRot3[exLetter]}")
Create function encrypt messages with cipher map
def encryptChars(plain, cipherMap):
upMessage = plain.upper()
cText = ""
for char in upMessage:
if char in alphaUpper: # Only encrypt uppercase characters
cText += cipherMap[char]
else:
cText += char # leave spaces, puntuation, etc. alone
return cText
# Try it
ctext = encryptChars("Time to go Windsurfing", createCMap(rotate(6, alphaUpper)))
print(ctext)
# Decipher it
tempText = encryptChars(ctext, createCMap(rotate(20, alphaUpper)))
print(tempText)
Challenge: decipher these messages!
From NCyTE
Brute force approach: Try out all possible keys.
Encrypted message: OYP FEK KIP KYVD RCC? TEDGLKVIJ RIV WRJK.
ctext = "OYP FEK KIP KYVD RCC? TEDGLKVIJ RIV WRJK."
for i in range(0,26):
text = encryptChars(ctext, createCMap(rotate(i, alphaUpper)))
print(f"try {i+1} text: {text}")
Trying them all:
From NCyTE
Auguste Kerckhoffs (1835-1903) Dutch linguist and cryptographer
A cryptosystem should be secure even if everything about the system, except the key, is public knowledge.
Contrast “Security by obscurity” with Kerckhoffs’s Principle.
Saltzer and Schroeder 1975, from CyBOK Intro
The security of the control must not rely on the secrecy of how it operates, but only on well specified secrets or passwords. This principle underpins cyber security as a field of open study: it allows scholars, engineers, auditors, and regulators to examine how security controls operate to ensure their correctness, or identify flaws, without undermining their security. The opposite approach, often called ‘security by obscurity’, is fragile as it restricts who may audit a security control, and is ineffective against insider threats or controls that can be reverse engineered.
Clearly state assumptions on what an attacker may have. Following Kerckhoffs’s Principle, we assume that the details of the algorithm used for encryption is known. Does the attacker have:
From An Introduction to Cryptography:
In this cipher, each letter/character in the plaintext alphabet is substituted by a different letter/character in the ciphertext alphabet.
If the alphabet we are using for the plaintext and ciphertext are both letters in the English alphabet, then the substitution cipher substitutes each letter for a different letter. In this case, the key is a reordering of the letters in the alphabet.
For example, the key ZYXWVUTSRQPONMLKJIHGFEDCBA would mean A is mapped to Z, B is mapped to Y, etc.
We use the Python random
standard library module
import random
alphaUpper = "ABCDEFGHIJKLMONPQRSTUVWXYZ"
randSub = random.sample(alphaUpper, len(alphaUpper))
print("".join(randSub)) # Join the list of characters into a string
randSub = random.sample(alphaUpper, len(alphaUpper))
print("".join(randSub)) # Join the list of characters into a string
randSub = random.sample(alphaUpper, len(alphaUpper))
print("".join(randSub)) # Join the list of characters into a string
You use sherlockHolmes.txt or any text you like
randSub = random.sample(alphaUpper, len(alphaUpper))
# You can use any text that you want here
sherlock = open("sherlockHolmes.txt", "r", encoding="utf8")
book = sherlock.read()
cBook = encryptChars(book, createCMap(randSub))
print(cBook[690:1240])
A book encrypted with our substitution cipher:
def sortedFreqs(text):
freqs = {} # Set up a dict to track letter counts
for char in alphaUpper:
freqs[char] = 0
for char in text: # Got through the text
upper = char.upper()
if upper in alphaUpper: # only consider letters
freqs[upper] += 1
letters = list(freqs.items()) # get dictionary as tuples
letters.sort(key=lambda x: -x[1]) # Sort based on frequency
return letters
cCommonFreqs = sortedFreqs(cBook)
print(cCommonFreqs)
cMostCommon = [x[0] for x in cCommonFreqs]
print("".join(cMostCommon))
print(mostCommon)
# [('Y', 54972), ('X', 40545), ('I', 36147), ('K', 34868), ('T', 31241), ('S', 29701), ('D', 29589), ('P', 27943), ('O', 25710), ('W', 19065), ('F', 17634), ('U', 13605), ('J', 12151), ('C', 11555), ('Z', 11119), ('H', 9777), ('A', 9363), ('N', 8313), ('M', 7240), ('G', 6646), ('Q', 4568), ('V', 3685), ('L', 579), ('E', 545), ('B', 438), ('R', 153)]
# YXIKTSDPOWFUJCZHANMGQVLEBR
# ETAOINSHRDLCUMWFGYPBVKJXQZ
def createDMap(sampFreq, actualFreq):
"""Creates a decipher map for simple decryption.
sampFreq is a list/string of most frequent to least frequent letters seen in sample
actualFreq is theoretical or known frequencies
Returns a dictionary that can be used to decipher characters
"""
mapDict = {}
for i, v in enumerate(sampFreq):
mapDict[v] = actualFreq[i]
return mapDict
# Use it to decrypt
dMap1 = createDMap(cMostCommon, mostCommon)
dbook1 = encryptChars(cBook, dMap1)
print(dbook1[690:1240])
Compare Letter Frequency of Book to “Common”
# Check letter frequencies of the book
bookFreqs = sortedFreqs(book)
# Most frequent
bookCommon = [x[0] for x in bookFreqs]
print("".join(bookCommon))
print(mostCommon)
# ETAOINHSRDLUMWCYFGPBVKXJQZ
# ETAOINSHRDLCUMWFGYPBVKJXQZ
If we knew what book was being sent we would know the exact letter frequencies and use those to create our inverse substitution.
dMap2 = createDMap(cMostCommon, bookCommon)
dbook2 = encryptChars(cBook, dMap2)
print(dbook2[690:1240])
Can we make our life easier with “special” plaintext?
special = ""
for i, v in enumerate(alphaUpper):
special += (i+1)*v
print(special)
# ABBCCCDDDDEEEEEFFFFFFGGGGGGGHHHHHHHHIIIIIIIIIJJJJJJJJJJKKKKKKKKKKKLLLLLLLLLLLLMMMMMMMMMMMMMOOOOOOOOOOOOOONNNNNNNNNNNNNNNPPPPPPPPPPPPPPPPQQQQQQQQQQQQQQQQQRRRRRRRRRRRRRRRRRRSSSSSSSSSSSSSSSSSSSTTTTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVVVVVVWWWWWWWWWWWWWWWWWWWWWWWXXXXXXXXXXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYZZZZZZZZZZZZZZZZZZZZZZZZZZ
Do you see another pattern here?
randSub2 = random.sample(alphaUpper, len(alphaUpper)) # New substitution
secretStuff = encryptChars("Do not ever use this cipher in real life!", createCMap(randSub2))
print(secretStuff)
ctextSpecial = encryptChars(special, createCMap(randSub2))
print(ctextSpecial)
Try it!
specialFreqs = sortedFreqs(special)
cSpecialFreqs = sortedFreqs(ctextSpecial)
dMapSpecial = createDMap([x[0] for x in cSpecialFreqs], [x[0] for x in specialFreqs])
print(dMapSpecial)
print(encryptChars(secretStuff, dMapSpecial))