' Vigenère Cipher — encrypts/decrypts text using keyword-based polyalphabetic cipher
#COMPILE EXE
#DIM ALL

FUNCTION PBMAIN() AS LONG
    LOCAL plaintext AS STRING
    LOCAL keyword AS STRING
    LOCAL ciphertext AS STRING
    LOCAL decrypted AS STRING
    LOCAL keyLen AS LONG
    LOCAL textLen AS LONG
    LOCAL i AS LONG
    LOCAL p AS LONG
    LOCAL k AS LONG
    LOCAL c AS LONG
    LOCAL d AS LONG
    LOCAL keyIdx AS LONG
    LOCAL testCount AS LONG
    LOCAL passCount AS LONG
    LOCAL failCount AS LONG
    LOCAL lineStr AS STRING
    LOCAL keyChar AS STRING
    LOCAL textChar AS STRING
    LOCAL tempStr AS STRING
    testCount = 0
    passCount = 0
    failCount = 0
    PRINT "============================================"
    PRINT "        VIGENERE CIPHER"
    PRINT "============================================"
    PRINT ""
    PRINT "Encryption using keyword-based polyalphabetic substitution"
    PRINT ""
    plaintext = "HELLOWORLD"
    keyword = "KEY"
    PRINT "Plaintext:  " + plaintext
    PRINT "Keyword:    " + keyword
    PRINT ""
    keyLen = LEN(keyword)
    textLen = LEN(plaintext)
    ciphertext = ""
    FOR i = 1 TO textLen
        textChar = MID$(plaintext, i, 1)
        p = ASC(textChar) - 65
        keyIdx = ((i - 1) MOD keyLen) + 1
        keyChar = MID$(keyword, keyIdx, 1)
        k = ASC(keyChar) - 65
        c = (p + k) MOD 26
        ciphertext = ciphertext + CHR$(c + 65)
    NEXT i
    PRINT "Ciphertext: " + ciphertext
    PRINT ""
    decrypted = ""
    FOR i = 1 TO textLen
        textChar = MID$(ciphertext, i, 1)
        c = ASC(textChar) - 65
        keyIdx = ((i - 1) MOD keyLen) + 1
        keyChar = MID$(keyword, keyIdx, 1)
        k = ASC(keyChar) - 65
        p = (c - k + 26) MOD 26
        decrypted = decrypted + CHR$(p + 65)
    NEXT i
    PRINT "Decrypted:  " + decrypted
    testCount = testCount + 1
    IF decrypted = plaintext THEN
        passCount = passCount + 1
        PRINT "PASS"
    ELSE
        failCount = failCount + 1
        PRINT "FAIL"
    END IF
    PRINT ""
    PRINT "============================================"
    PRINT "     VIGENERE WITH MULTIPLE KEYWORDS"
    PRINT "============================================"
    PRINT ""
    LOCAL keywords(5) AS STRING
    LOCAL keyResults(5) AS STRING
    LOCAL keyDecrypts(5) AS STRING
    FOR j = 0 TO 4
        IF j = 0 THEN keyword = "KEY"
        IF j = 1 THEN keyword = "CODE"
        IF j = 2 THEN keyword = "CIPHER"
        IF j = 3 THEN keyword = "SECRET"
        IF j = 4 THEN keyword = "LONGKEYWORD"
        plaintext = "THISISATESTMESSAGE"
        keyLen = LEN(keyword)
        textLen = LEN(plaintext)
        ciphertext = ""
        FOR i = 1 TO textLen
            textChar = MID$(plaintext, i, 1)
            p = ASC(textChar) - 65
            keyIdx = ((i - 1) MOD keyLen) + 1
            keyChar = MID$(keyword, keyIdx, 1)
            k = ASC(keyChar) - 65
            c = (p + k) MOD 26
            ciphertext = ciphertext + CHR$(c + 65)
        NEXT i
        keyResults(j) = ciphertext
        decrypted = ""
        FOR i = 1 TO textLen
            textChar = MID$(ciphertext, i, 1)
            c = ASC(textChar) - 65
            keyIdx = ((i - 1) MOD keyLen) + 1
            keyChar = MID$(keyword, keyIdx, 1)
            k = ASC(keyChar) - 65
            p = (c - k + 26) MOD 26
            decrypted = decrypted + CHR$(p + 65)
        NEXT i
        keyDecrypts(j) = decrypted
        PRINT "Key '" + keyword + "': " + ciphertext
        testCount = testCount + 1
        IF decrypted = plaintext THEN
            passCount = passCount + 1
        ELSE
            failCount = failCount + 1
        END IF
    NEXT j
    PRINT ""
    PRINT "============================================"
    PRINT "     VIGENERE TABLE (KASISKI EXAMINATION)"
    PRINT "============================================"
    PRINT ""
    PRINT "Vigenere square (partial):"
    PRINT ""
    plaintext = "ABCDEFGHIJ"
    keyword = "AAAAA"
    keyLen = 5
    FOR j = 0 TO 5
        lineStr = "Key=" + CHR$(65 + j) + ": "
        FOR i = 1 TO 10
            textChar = MID$(plaintext, i, 1)
            p = ASC(textChar) - 65
            k = j
            c = (p + k) MOD 26
            lineStr = lineStr + CHR$(c + 65) + " "
        NEXT i
        PRINT lineStr
    NEXT j
    PRINT ""
    PRINT "============================================"
    PRINT "     LOWERCASE VIGENERE"
    PRINT "============================================"
    PRINT ""
    plaintext = "helloworld"
    keyword = "key"
    keyLen = LEN(keyword)
    textLen = LEN(plaintext)
    ciphertext = ""
    FOR i = 1 TO textLen
        textChar = MID$(plaintext, i, 1)
        p = ASC(textChar) - 97
        keyIdx = ((i - 1) MOD keyLen) + 1
        keyChar = MID$(keyword, keyIdx, 1)
        k = ASC(keyChar) - 97
        c = (p + k) MOD 26
        ciphertext = ciphertext + CHR$(c + 97)
    NEXT i
    decrypted = ""
    FOR i = 1 TO textLen
        textChar = MID$(ciphertext, i, 1)
        c = ASC(textChar) - 97
        keyIdx = ((i - 1) MOD keyLen) + 1
        keyChar = MID$(keyword, keyIdx, 1)
        k = ASC(keyChar) - 97
        p = (c - k + 26) MOD 26
        decrypted = decrypted + CHR$(p + 97)
    NEXT i
    PRINT "Lowercase test:"
    PRINT "  Plain:  " + plaintext
    PRINT "  Key:    " + keyword
    PRINT "  Cipher: " + ciphertext
    PRINT "  Decrypt: " + decrypted
    testCount = testCount + 1
    IF decrypted = plaintext THEN
        passCount = passCount + 1
    ELSE
        failCount = failCount + 1
    END IF
    PRINT ""
    PRINT "============================================"
    PRINT "     AUTO-KEY VIGENERE"
    PRINT "============================================"
    PRINT ""
    plaintext = "HELLOWORLD"
    keyword = "KEY"
    keyLen = LEN(keyword)
    textLen = LEN(plaintext)
    ciphertext = ""
    FOR i = 1 TO textLen
        textChar = MID$(plaintext, i, 1)
        p = ASC(textChar) - 65
        IF i <= keyLen THEN
            keyIdx = i
        ELSE
            keyIdx = i - keyLen
        END IF
        IF i <= keyLen THEN
            keyChar = MID$(keyword, i, 1)
        ELSE
            keyChar = MID$(plaintext, i - keyLen, 1)
        END IF
        k = ASC(keyChar) - 65
        c = (p + k) MOD 26
        ciphertext = ciphertext + CHR$(c + 65)
    NEXT i
    PRINT "Auto-key ciphertext: " + ciphertext
    PRINT ""
    PRINT "Results: " + STR$(passCount) + " passed, " + STR$(failCount) + " failed"
    FUNCTION = 0
END FUNCTION
