Skip to content

Instantly share code, notes, and snippets.

@Pharap
Last active March 28, 2019 00:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pharap/a1559a1e77d2d00471549f9acdae65dc to your computer and use it in GitHub Desktop.
Save Pharap/a1559a1e77d2d00471549f9acdae65dc to your computer and use it in GitHub Desktop.
Vignere Cipher
#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