diff --git a/Fall-2024/CS-3333/Assignments/RSA-Project/.clang-format b/Fall-2024/CS-3333/Assignments/RSA-Project/.clang-format new file mode 100644 index 0000000..6d0211b --- /dev/null +++ b/Fall-2024/CS-3333/Assignments/RSA-Project/.clang-format @@ -0,0 +1,244 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseColons: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: ".*" + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: "(Test)?$" +IncludeIsMainSourceRegex: "" +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +KeepEmptyLinesAtEOF: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: "" +MacroBlockEnd: "" +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE diff --git a/Fall-2024/CS-3333/Assignments/RSA-Project/docs/NIST.FIPS.186-5.pdf b/Fall-2024/CS-3333/Assignments/RSA-Project/docs/NIST.FIPS.186-5.pdf new file mode 100644 index 0000000..549aa0f Binary files /dev/null and b/Fall-2024/CS-3333/Assignments/RSA-Project/docs/NIST.FIPS.186-5.pdf differ diff --git a/Fall-2024/CS-3333/Assignments/RSA-Project/docs/RSA Logical basis and construction.pptx b/Fall-2024/CS-3333/Assignments/RSA-Project/docs/RSA Logical basis and construction.pptx new file mode 100644 index 0000000..4ded5e4 Binary files /dev/null and b/Fall-2024/CS-3333/Assignments/RSA-Project/docs/RSA Logical basis and construction.pptx differ diff --git a/Fall-2024/CS-3333/Assignments/RSA-Project/docs/RSA Project.pdf b/Fall-2024/CS-3333/Assignments/RSA-Project/docs/RSA Project.pdf new file mode 100644 index 0000000..6dd3481 Binary files /dev/null and b/Fall-2024/CS-3333/Assignments/RSA-Project/docs/RSA Project.pdf differ diff --git a/Fall-2024/CS-3333/Assignments/RSA-Project/src/main.c b/Fall-2024/CS-3333/Assignments/RSA-Project/src/main.c new file mode 100644 index 0000000..a5905d9 --- /dev/null +++ b/Fall-2024/CS-3333/Assignments/RSA-Project/src/main.c @@ -0,0 +1,213 @@ +#include +#include +#include + +bool isPrime(unsigned long num) { + for (int i = 2; i * i <= num; i++) { + if (num % i == 0) { + return false; + } + } + return true; +} + +/** + * @brief Calculate the great common divisor (GCD) of two numbers recursively + * + * @param a first number + * @param b second number + * @return the gcd of both numbers + */ +unsigned long gcd(unsigned long a, unsigned long b) { + // NOTE: This really should be iterative with a while loop, recursion here + // is not ideal + return (b == 0) ? a : gcd(b, a % b); +} + +/** + * @brief Calculate the great common divisor (GCD) of two numbers recursively + * via the Extended Euclidean Algorithm + * + * @param a First number to find GCD against b + * @param b Second number to find GCD against a + * @return the gcd of both numbers + */ +signed long long gcdExtended(signed long long a, signed long long b, + signed long long *x, signed long long *y) { + + // Base Case + if (a == 0) { + *x = 0, *y = 1; + return b; + } + + // To store results of recursive call + signed long long x1, y1; + signed long long gcd = gcdExtended(b % a, a, &x1, &y1); + + // Update x and y using results of recursive + // call + *x = y1 - (b / a) * x1; + *y = x1; + + return gcd; +} + +/** + * @brief Calculate the modulo inverse using the extended Euclidean Algorithm + * + * @param a The value to be inverted mod a + * @param m The modulus, a positive integer greater than 1 + */ +unsigned long modInverse(unsigned long a, unsigned long m) { + // You might notice the evil casting going on below. There's a really good + // reason for that! The extended euclidean algo. pretty much has a hard + // requirement on using signed integers. To satisfy this condition, we're + // using `signed long long` so we can safely fit the *unsigned long* value + // within. This allows "safe" casts back and forth without any loss. + // + // Some more enlightening information on this problem can be found at + // https://jeffhurchalla.com/2018/10/13/implementing-the-extended-euclidean-algorithm-with-unsigned-inputs/ + // + // Frankly, there are much, MUCH, faster ways of doing this if we didn't + // *have* to use the extended euclidean algo. (mostly in the form of cursed + // bitshifting which FIPS-186-5 has some resources on 😉). + signed long long x, y, a_0 = (signed long long)a, m_0 = (signed long long)m; + signed long long g = gcdExtended(a_0, m_0, &x, &y); + if (g != 1) { + fprintf(stderr, + "Failed to determine modular inverse for `%lu` and `%lu`, they " + "may not be coprime!\n", + a, m); + exit(EXIT_FAILURE); + } + return (unsigned long)((x % m_0 + m_0) % m_0); +} + +/** + * @brief Modular Exponentiation + * + * See + * https://www.cs.ucf.edu/~dmarino/ucf/cis3362/lectures/newlecs/FastModExpo.pdf + * for more information + */ +unsigned long modExp(unsigned long base, unsigned long exp, unsigned long num) { + if (exp == 0) + return 1; + if (exp == 1) + return base % num; + if (exp % 2 == 0) { + int t = modExp(base, exp / 2, num); + return (t * t) % num; + } + return (base * modExp(base, exp - 1, num)) % num; +} + +unsigned long rprime(unsigned n) { + unsigned r = rand(), t; + while ((t = gcd(r, n)) > 1) { + r /= t; + } + return r; +} + +/** + * @brief Generate keys for RSA encryption given some p & q primes + * + * @param p first secret large prime number + * @param q second secret large primer number + * @param n will be set to the result of p * q + * @param e randomly chosen such that e < φ(n) and e & φ (n) are coprime + * @param d the mod inverse of e % φ(n), where e*d ≡ 1 (mod φ(n)) + */ +void generateKeys(unsigned long p, unsigned long q, unsigned long *n, + unsigned long *e, unsigned long *d) { + *n = p * q; + unsigned long phi = (p - 1) * (q - 1); + + while (gcd(*e, phi) != 1 && *e < phi) { + (*e)++; + } + + if (*e >= phi) { + fprintf(stderr, + "Failed to find valid `e` value for given `phi` value! `e`: " + "'%lu' | `phi`: '%lu'\n", + *e, phi); + exit(EXIT_FAILURE); + } + + *d = modInverse(*e, phi); +} + +/** + * @brief Encrypt plaintext with RSA + * + * @param plaintext + * @param e Encryption key + * @param n Combined secret values + */ +unsigned long encrypt(unsigned long plaintext, unsigned long e, + unsigned long n) { + return modExp(plaintext, e, n); +} + +// Function to decrypt ciphertext using RSA +/** + * @brief Decrypt RSA encrypted ciphertext + * + * @param ciphertext The text to decrypt + * @param d Decryption key + * @param n Combined secret values + */ +unsigned long decrypt(unsigned long ciphertext, unsigned long d, + unsigned long n) { + return modExp(ciphertext, d, n); +} + +int main() { + unsigned long p = 7; // prime number, try 3, 5, 7, 11, 13, ... + unsigned long q = 541; // prime number, try 3, 5, 7, 11, 13, ... + unsigned long e = 7; + + unsigned long n, d; + + // printf("Enter p and q: "); + // scanf("%lu %lu", &p, &q); + // Generate RSA keys + generateKeys(p, q, &n, &e, &d); + + if (!isPrime(p)) { + fprintf(stderr, "Given `p` value was not prime, received '%lu'!\n", p); + exit(EXIT_FAILURE); + } + + if (!isPrime(q)) { + fprintf(stderr, "Given `q` value was not prime, received '%lu'!\n", q); + exit(EXIT_FAILURE); + } + + printf("Public key (e, n): (%lu, %lu)\n", e, n); + printf("Private key (d, n): (%lu, %lu)\n\n", d, n); + + // Encrypt and decrypt a sample plaintext, which we assume is given as an + // integer value + unsigned long plaintext; + printf("Enter an integer between 0 and %lu as plain text to be encrypted: ", + n - 1); + int _ = scanf("%lu", &plaintext); + if (plaintext > n - 1) { + fprintf(stderr, + "Unable to RSA encrypt & decrypt given `plaintext`: " + "'%lu'!\nPlaintext value was more than `n-1`: '%lu'\n", + plaintext, n - 1); + exit(EXIT_FAILURE); + } + printf("Original plaintext: %lu\n", plaintext); + unsigned long ciphertext = encrypt(plaintext, e, n); + printf("Encrypted ciphertext: %lu\n", ciphertext); + unsigned long decrypted = decrypt(ciphertext, d, n); + printf("Decrypted plaintext: %lu\n\n", decrypted); + + return 0; +}