cryptography
카이사르 암호
수색…
소개
그것은 각각의 문자가 원형 알파벳 순서 (즉, Z가 A 인 문자)를 사용하여 문자 3 위치 (실제 Caesar 암호)로 대체되는 간단한 이동 monoalphabetic 고전 암호입니다. 그래서 우리가 HELLO WORLD를 부호화 할 때 암호문은 KHOORZRUOG가됩니다.
소개
카이사르 암호는 고전적인 암호화 방법입니다. 문자를 일정량 씩 이동하여 작동합니다. 예를 들어, 시프트 3을 선택하면 A는 D가되고 E는 H가됩니다.
다음 텍스트는 23 시프트를 사용하여 암호화되었습니다.
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
파이썬 구현
ASCII 방식
이것은 문자를 이동하지만 새 문자가 문자가 아닌지 상관하지 않습니다. 구두점 또는 특수 문자를 사용하려는 경우에 적합하지만 출력으로 만 문자를 제공 할 필요는 없습니다. 예를 들어, "z"3은 "}"로 이동합니다.
def ceasar(text, shift):
output = ""
for c in text:
output += chr(ord(c) + shift)
return output
ROT13
ROT13은 카이사르 암호의 특별한 경우이며, 13 시프트입니다. 글자 만 변경되고 공백과 특수 문자는 그대로 남습니다.
흥미로운 점은 ROT13을 상호 암호로 사용한다는 것입니다. ROT13을 두 번 적용하면 초기 입력이 제공됩니다. 실제로, 2 * 13 = 26, 알파벳의 글자 수.
ROT13은 입력 매개 변수로서 키를 가지지 않으므로 인코딩 알고리즘 또는 더 구체적으로 암호가 아닌 난독 화 알고리즘으로 더 많이 사용됩니다.
ROT13은 메시지를 직접 읽을 수 없으므로 불쾌한 메시지 나 농담으로 자주 사용됩니다. 어떤 계산상의 보안도 제공하지 않습니다.
Caesar Cipher의 Java 구현
카이사르 암호의 구현.
- 이 구현은 대문자와 소문자 알파벳에서만 시프트 연산을 수행하고 다른 문자 (예 : 그대로 공백)를 유지합니다.
- 카이사르 암호는 현재 표준에 따라 안전하지 않습니다.
- 아래 예는 설명을위한 것입니다!
- 참조 : [ https://en.wikipedia.org/wiki/Caesar_cipher](https://en.wikipedia.org/wiki/Caesar_cipher)
package com.example.so.cipher;
/**
* Implementation of the Caesar cipher.
* <p>
* <ul>
* <li>This implementation performs the shift operation only on upper and lower
* case alphabets and retains the other characters (such as space as-is).</li>
* <li>The Caesar cipher is not secure as per current standards.</li>
* <li>Below example is for illustrative purposes only !</li>
* <li>Reference: https://en.wikipedia.org/wiki/Caesar_cipher</li>
* </ul>
* </p>
*
* @author Ravindra HV
* @author Maarten Bodewes (beautification only)
* @since 2016-11-21
* @version 0.3
*
*/
public class CaesarCipher {
public static final char START_LOWER_CASE_ALPHABET = 'a'; // ASCII-97
public static final char END_LOWER_CASE_ALPHABET = 'z'; // ASCII-122
public static final char START_UPPER_CASE_ALPHABET = 'A'; // ASCII-65
public static final char END_UPPER_CASE_ALPHABET = 'Z'; // ASCII-90
public static final int ALPHABET_SIZE = 'Z' - 'A' + 1; // 26 of course
/**
* Performs a single encrypt followed by a single decrypt of the Caesar
* cipher, prints out the intermediate values and finally validates
* that the decrypted plaintext is identical to the original plaintext.
*
* <p>
* This method outputs the following:
*
* <pre>
* Plaintext : The quick brown fox jumps over the lazy dog
* Ciphertext : Qeb nrfzh yoltk clu grjmp lsbo qeb ixwv ald
* Decrypted : The quick brown fox jumps over the lazy dog
* Successful decryption: true
* </pre>
* </p>
*
* @param args (ignored)
*/
public static void main(String[] args) {
int shift = 23;
String plainText = "The quick brown fox jumps over the lazy dog";
System.out.println("Plaintext : " + plainText);
String ciphertext = caesarCipherEncrypt(plainText, shift);
System.out.println("Ciphertext : " + ciphertext);
String decrypted = caesarCipherDecrypt(ciphertext, shift);
System.out.println("Decrypted : " + decrypted);
System.out.println("Successful decryption: "
+ decrypted.equals(plainText));
}
public static String caesarCipherEncrypt(String plaintext, int shift) {
return caesarCipher(plaintext, shift, true);
}
public static String caesarCipherDecrypt(String ciphertext, int shift) {
return caesarCipher(ciphertext, shift, false);
}
private static String caesarCipher(
String input, int shift, boolean encrypt) {
// create an output buffer of the same size as the input
StringBuilder output = new StringBuilder(input.length());
for (int i = 0; i < input.length(); i++) {
// get the next character
char inputChar = input.charAt(i);
// calculate the shift depending on whether to encrypt or decrypt
int calculatedShift = (encrypt) ? shift : (ALPHABET_SIZE - shift);
char startOfAlphabet;
if ((inputChar >= START_LOWER_CASE_ALPHABET)
&& (inputChar <= END_LOWER_CASE_ALPHABET)) {
// process lower case
startOfAlphabet = START_LOWER_CASE_ALPHABET;
} else if ((inputChar >= START_UPPER_CASE_ALPHABET)
&& (inputChar <= END_UPPER_CASE_ALPHABET)) {
// process upper case
startOfAlphabet = START_UPPER_CASE_ALPHABET;
} else {
// retain all other characters
output.append(inputChar);
// and continue with the next character
continue;
}
// index the input character in the alphabet with 0 as base
int inputCharIndex =
inputChar - startOfAlphabet;
// cipher / decipher operation (rotation uses remainder operation)
int outputCharIndex =
(inputCharIndex + calculatedShift) % ALPHABET_SIZE;
// convert the new index in the alphabet to an output character
char outputChar =
(char) (outputCharIndex + startOfAlphabet);
// add character to temporary-storage
output.append(outputChar);
}
return output.toString();
}
}
프로그램 출력 :
Plaintext : The quick brown fox jumps over the lazy dog
Ciphertext : Qeb nrfzh yoltk clu grjmp lsbo qeb ixwv ald
Decrypted : The quick brown fox jumps over the lazy dog
Successful decryption: true
파이썬 구현
다음 코드 예제는 Caesar 암호를 구현하고 암호의 속성을 보여줍니다.
대문자와 소문자 모두 영숫자 문자를 처리하고 다른 모든 문자는 그대로 유지합니다.
카이사르 암호의 다음 속성이 표시됩니다.
- 약한 열쇠;
- 낮은 키 공간;
- 각 키가 역 (역) 키를 갖는다는 사실;
- ROT13와의 관계;
또한보다 일반적인 - 암호화 개념을 보여줍니다 :
- 약한 열쇠;
- 난독 화 (키가없는)와 암호화의 차이;
- 무차별 강요하는 키;
- 암호문의 누락 된 무결성.
def caesarEncrypt(plaintext, shift):
return caesarCipher(True, plaintext, shift)
def caesarDecrypt(ciphertext, shift):
return caesarCipher(False, ciphertext, shift)
def caesarCipher(encrypt, text, shift):
if not shift in range(0, 25):
raise Exception('Key value out of range')
output = ""
for c in text:
# only encrypt alphanumerical characters
if c.isalpha():
# we want to shift both upper- and lowercase characters
ci = ord('A') if c.isupper() else ord('a')
# if not encrypting, we're decrypting
if encrypt:
output += caesarEncryptCharacter(c, ci, shift)
else:
output += caesarDecryptCharacter(c, ci, shift)
else:
# leave other characters such as digits and spaces
output += c
return output
def caesarEncryptCharacter(plaintextCharacter, positionOfAlphabet, shift):
# convert character to the (zero-based) index in the alphabet
n = ord(plaintextCharacter) - positionOfAlphabet
# perform the >positive< modular shift operation on the index
# this always returns a value within the range [0, 25]
# (note that 26 is the size of the western alphabet)
x = (n + shift) % 26 # <- the magic happens here
# convert the index back into a character
ctc = chr(x + positionOfAlphabet)
# return the result
return ctc
def caesarDecryptCharacter(plaintextCharacter, positionOfAlphabet, shift):
# convert character to the (zero-based) index in the alphabet
n = ord(plaintextCharacter) - positionOfAlphabet
# perform the >negative< modular shift operation on the index
x = (n - shift) % 26
# convert the index back into a character
ctc = chr(x + positionOfAlphabet)
# return the result
return ctc
def encryptDecrypt():
print '--- Run normal encryption / decryption'
plaintext = 'Hello world!'
key = 3 # the original value for the Caesar cipher
ciphertext = caesarEncrypt(plaintext, key)
print ciphertext
decryptedPlaintext = caesarDecrypt(ciphertext, key)
print decryptedPlaintext
encryptDecrypt()
print '=== Now lets show some cryptographic properties of the Caesar cipher'
def withWeakKey():
print '--- Encrypting plaintext with a weak key is not a good idea'
plaintext = 'Hello world!'
# This is the weakest key of all, it does nothing
weakKey = 0
ciphertext = caesarEncrypt(plaintext, weakKey)
print ciphertext # just prints out the plaintext
withWeakKey();
def withoutDecrypt():
print '--- Do we actually need caesarDecrypt at all?'
plaintext = 'Hello world!'
key = 3 # the original value for the Caesar cipher
ciphertext = caesarEncrypt(plaintext, key)
print ciphertext
decryptionKey = 26 - key; # reciprocal value
decryptedPlaintext = caesarEncrypt(ciphertext, decryptionKey)
print decryptedPlaintext # performed decryption
withoutDecrypt()
def punnify():
print '--- ROT 13 is the Caesar cipher with a given, reciprocal, weak key: 13'
# The key is weak because double encryption will return the plaintext
def rot13(pun):
return caesarEncrypt(pun, 13)
print 'Q: How many marketing people does it take to change a light bulb?'
obfuscated = 'N: V jvyy unir gb trg onpx gb lbh ba gung.'
print obfuscated
deobfuscated = rot13(obfuscated)
print deobfuscated
# We should not leak the pun, right? Lets obfuscate afterwards!
obfuscatedAgain = rot13(deobfuscated)
print obfuscatedAgain
punnify()
def bruteForceAndLength():
print '--- Brute forcing is very easy as there are only 25 keys in the range [1..25]'
# Note that AES-128 has 340,282,366,920,938,463,463,374,607,431,768,211,456 keys
# and is therefore impossible to bruteforce (if the key is correctly generated)
key = 10;
plaintextToFind = 'Hello Maarten!'
ciphertextToBruteForce = caesarEncrypt(plaintextToFind, key)
for candidateKey in range(1, 25):
bruteForcedPlaintext = caesarDecrypt(ciphertextToBruteForce, candidateKey)
# lets assume the adversary knows 'Hello', but not the name
if bruteForcedPlaintext.startswith('Hello'):
print 'key value: ' + str(candidateKey) + ' gives : ' + bruteForcedPlaintext
print '--- Length of plaintext usually not hidden'
# Side channel attacks on ciphertext lengths are commonplace! Beware!
if len(ciphertextToBruteForce) != len('Hello Stefan!'):
print 'The name is not Stefan (but could be Stephan)'
bruteForceAndLength()
def manInTheMiddle():
print '--- Ciphers are vulnerable to man-in-the-middle attacks'
# Hint: do not directly use a cipher for transport security
moneyTransfer = 'Give Maarten one euro'
key = 1
print moneyTransfer
encryptedMoneyTransfer = caesarEncrypt(moneyTransfer, key)
print encryptedMoneyTransfer
# Man in the middle replaces third word with educated guess
# (or tries different ciphertexts until success)
encryptedMoneyTransferWords = encryptedMoneyTransfer.split(' ');
encryptedMoneyTransferWords[2] = 'ufo' # unidentified financial object
modifiedEncryptedMoneyTransfer = ' '.join(encryptedMoneyTransferWords)
print modifiedEncryptedMoneyTransfer
decryptedMoneyTransfer = caesarDecrypt(modifiedEncryptedMoneyTransfer, key)
print decryptedMoneyTransfer
manInTheMiddle()