Last active
March 28, 2019 00:49
-
-
Save Pharap/a1559a1e77d2d00471549f9acdae65dc to your computer and use it in GitHub Desktop.
Vignere Cipher
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
// | |
// Copyright (C) 2019 Pharap (@Pharap) | |
// | |
// 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. | |
// | |
// For uint8_t | |
#include <stdint.h> | |
constexpr bool isUppercase(char c) | |
{ | |
return ((c >= 'A') && (c <= 'Z')); | |
} | |
constexpr bool isLowercase(char c) | |
{ | |
return ((c >= 'a') && (c <= 'z')); | |
} | |
enum class CharacterCase : uint8_t | |
{ | |
Invalid, | |
Uppercase, | |
Lowercase, | |
}; | |
// Returns true if the character can be encoded | |
constexpr CharacterCase getCharacterCase(char c) | |
{ | |
return (isUppercase(c)) ? CharacterCase::Uppercase : (isLowercase(c)) ? CharacterCase::Lowercase : CharacterCase::Invalid; | |
} | |
// An invalid index | |
constexpr uint8_t invalidIndex = 0xFF; | |
// Get the lookup index for the given character. | |
// Only a-z and A-Z are valid inputs, other values return the invalid value 0xFF. | |
inline uint8_t characterToIndex(char c) | |
{ | |
// If character is between 'a' and 'z' | |
if(isLowercase(c)) | |
{ | |
// Subtract 'a' from c to get a value between 0 and 25 | |
char result = (c - 'a'); | |
// Convert the char to a uint8_t (unsigned char) | |
uint8_t index = static_cast<uint8_t>(result); | |
// Return the index | |
return index; | |
} | |
// If character is between 'A' and 'Z' | |
if(isUppercase(c)) | |
{ | |
// Subtract 'A' from c to get a value between 0 and 25 | |
char result = (c - 'A'); | |
// Convert the char to a uint8_t (unsigned char) | |
uint8_t index = static_cast<uint8_t>(result); | |
// Return the index | |
return index; | |
} | |
// If the character was not between 'a' and 'z' or between 'A' and 'Z' | |
// return an invalid index. | |
return invalidIndex; | |
} | |
// Get the character for the given index. | |
// Returns a character between 'a' and 'z' for a value between 0 and 25 | |
// Returns the specified default character for any other value | |
constexpr char indexToLowercaseCharacter(uint8_t index, char defaultCharacter) | |
{ | |
return (index < 26) ? ('a' + static_cast<char>(index)) : defaultCharacter; | |
} | |
// Get the character for the given index. | |
// Returns a character between 'A' and 'Z' for a value between 0 and 25 | |
// Returns the specified default character for any other value | |
constexpr char indexToUppercaseCharacter(uint8_t index, char defaultCharacter) | |
{ | |
return (index < 26) ? ('A' + static_cast<char>(index)) : defaultCharacter; | |
} | |
// Perform a Caesar cipher shift | |
inline uint8_t caesarCipherShift(uint8_t inputIndex, uint8_t shiftAmount) | |
{ | |
return ((inputIndex + shiftAmount) % 26); | |
} | |
// Encode a single character using the Vignere cipher | |
inline char vignereCipherEncode(char inputCharacter, char keyCharacter, char defaultCharacter) | |
{ | |
const CharacterCase characterCase = getCharacterCase(inputCharacter); | |
// If input character isn't uppercase or lowercase then it can't be encoded, | |
// so return the input character unchanged | |
if(characterCase == CharacterCase::Invalid) | |
return inputCharacter; | |
// Transform the input character into an index | |
uint8_t inputIndex = characterToIndex(inputCharacter); | |
// Transform the key character into an index | |
uint8_t keyIndex = characterToIndex(keyCharacter); | |
// Perform a caesar cipher on the input index, | |
// using the key index as a shift amount | |
uint8_t shiftedIndex = caesarCipherShift(inputIndex, keyIndex); | |
// Convert the shifted index into a character to get the encoded character | |
if(characterCase == CharacterCase::Uppercase) | |
return indexToUppercaseCharacter(shiftedIndex, defaultCharacter); | |
else | |
return indexToLowercaseCharacter(shiftedIndex, defaultCharacter); | |
} | |
// The input buffer and the output buffer may only overlap if | |
// the first character of the input buffer is at or after | |
// the first character of the output buffer | |
inline void vignereCipherEncode(const char inputBuffer[], char outputBuffer[], size_t bufferSize, const char key[], size_t keySize, char defaultCharacter) | |
{ | |
const size_t lastKeyIndex = (keySize - 1); | |
for(size_t index = 0, keyIndex = 0; index < bufferSize; ++index) | |
{ | |
// Get the character to be encoded | |
char inputCharacter = inputBuffer[index]; | |
// Get the key character to be used in the encoding | |
char keyCharacter = key[keyIndex]; | |
// Encode the character by applying a single step of the vignere cipher | |
char encodedCharacter = vignereCipherEncode(inputCharacter, keyCharacter, defaultCharacter); | |
// Write the encoded character into the output buffer | |
outputBuffer[index] = encodedCharacter; | |
// If the key index isn't at the end of the key | |
if(keyIndex < lastKeyIndex) | |
{ | |
// Increment the key index | |
++keyIndex; | |
} | |
else | |
{ | |
// Otherwise reset the key index to the start of the key | |
keyIndex = 0; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment