This is actually a really good demonstration of efficiency in Power Automate. My son asked me the question, can you encrypt and decrypt a string using a key and Viginere Cipher? They’ve just covered this technique in school. In this post, not only do I demo how it can be done, I also show how it can be done without an Apply to Each. There is also a live version of the solution allowing you to encrypt and decrypt your own strings using your own code word.

## What is the Viginere Cipher?

The Vigenere cipher was invented by Blaise de Vigenere in the 16th century. It is a method of encrypting alphabetic text by using a series of interwoven Caesar ciphers, with each letter of the plaintext being shifted based on a keyword.

To encrypt a message using the Vigenere cipher, a keyword or phrase is chosen, and each letter of the message is shifted according to the corresponding letter of the keyword. For example, if the keyword is “LEMON” and the plaintext is “HELLO”, the first letter of the plaintext is shifted by “L”, the second letter by “E”, the third letter by “M”, the fourth letter by “O”, and the fifth letter by “N”. The resulting ciphertext would be “RIJVS”.

To decrypt a message using the Vigenere cipher, the recipient would need to know the keyword that was used to encrypt the message. The recipient would then use the same keyword to shift each letter of the ciphertext back to its original plaintext letter.

The Vigenere cipher was considered unbreakable for many years, until Charles Babbage and Friedrich Kasiski independently discovered a method for breaking it in the mid-19th century. This was done by identifying repeated patterns in the ciphertext, which allowed them to determine the length of the keyword. Once the length of the keyword was known, the cipher could be broken using frequency analysis.

Despite its vulnerability to modern decryption methods, the Vigenere cipher remains an important historical encryption technique and is still used in some limited applications today.

## Trigger the Flow from Microsoft Forms

This seemed like the obvious way to demonstrate this and allow you to encrypt and decrypt your own strings using the Power Platform. Remember, **DO NOT SHARE ANYTHING CONFIDENTIAL**, including the code word. In order to receive your encrypted/decrypted string, you must supply a valid email address or Power Automate won’t be able to email you with the supplied answer.

## The Power Automate Flow

The flow consists of a trigger for the Form, followed by get response details and then I have a scope containing all of the necessary actions. Some of these actions could be combined with more complex expressions but I decided to keep them seperate as they don’t effect performance. The flow runs in under 1 second.

Note that in my implementation, spaces, numerical and symbols are included in the shift using a secret but remain the same and do not change. Similar implementations online will remove spaces and/or numbers.

Initially I created a grid array of the letters and the shifted patterns, 26 of each, but then I realised it was easier to get the flow to simply create a string from the code word that repeated up until the length of the string to be encrypted/decrypted, work out the index of these letters and then work out the index of the letters for the string. With these indexes it is then possible to add on the shift, use modulus to get the remainder on string length 26 and return the new character based on the calculated shift for each letter using the code word.

And this is what the Flow looks like:

## In More Detail

I will now explain the actions in more detail as follows:

ComposeAlphabet: is used to define the letters that we are looking to shift and it will also allow us to calculate the index of the letter based on their position.

ComposeAlphabetArray: using expression **chunk(outputs(‘ComposeAlphabet’), 1)** an array is created of all the letters.

ComposeSecret: the secret code word from my Microsoft Form.

SelectSplitSecretAndFindLetterNo: Two expressions in this one, the first is **chunk(outputs(‘ComposeSecret’), 1)** and this is so that our secret string is now an array of letters. The second expression in the Map (text mode) **indexOf(outputs(‘ComposeAlphabet’), item())** is used to calculate the index of the secret word letters based on the opening alphabet string. A=0, B=1 … Z=25. As objects in an array can be selected by integer indexes, this works nicely for our efficient script (demos of this on my YouTube videos)

ComposeString: is the string to be encrypted or decrypted from the Microsoft Form.

SelectSecretSequence: Two expressions here, the first **range(0, length(outputs(‘ComposeString’)))** creates an array based on the length of the string starting from 0. We can then use this to our advantage in the map so that we can repeat our code word for the length of the string. I.e. if codeword is Cat and string is Damien, the sequence would be CatCat. The second expression is **body(‘SelectSplitSecretAndFindLetterNo’)?[mod(item(), length(outputs(‘ComposeSecret’)))]** and it is selecting the letter from the secret based on the modulus i.e. remainder. If the code word is 3 in length, 0 mod 3 is 0, 1 mod 3 is 1, 4 mod 3 is 1. Using the result we can retrieve the letter from the secret word array based on integer index [0] [1] [2] etc.

ComposeStringArray: creating an array of letters with **chunk(outputs(‘ComposeString’), 1)**

SelectStringSequence: two expressions here, the first **range(0, length(outputs(‘ComposeString’)))** is based on an array of numbers, starting from 0 and of size based on the length of the string. The second in the map is **indexof(outputs(‘ComposeAlphabet’), outputs(‘ComposeStringArray’)?[item()])** where we are returning the index of each letter in the string based on our alphabet string. This gives us an array of indexes.

Condition: the purpose of this is to branch yes or no based on the the string Encrypt or not, i.e. Decrypt, so that the appropriate logic is applied to the indexes that have been calculated above. For a Encrypt they are added for a decrypt the process is reversed.

## Encrypt

SelectOffsetEncrypt: two expressions the from is based on **range(0, length(outputs(‘ComposeString’)))** which we have seen multiple times now, the map is **mod(add(body(‘SelectSecretSequence’)?[item()], body(‘SelectStringSequence’)?[item()]), 26)** where we are adding the secret sequence index and the string sequence index, using mod 26 to return the remainder and this becomes are new letter index. This creates an array of new letter indexes.

SelectEncryptedLetters: two expressions, again the trusty **range(0, length(outputs(‘ComposeString’)))** as the from, with **if(equals(body(‘SelectStringSequence’)?[item()], -1), outputs(‘ComposeStringArray’)?[item()], outputs(‘ComposeAlphabetArray’)?[body(‘SelectOffsetEncrypt’)?[item()]])** as the map. This is checking to see if the sequence equals -1, in which case indexof could not find the letter in the previous select actions and we are most likely dealing with a number or symbol. If it equals 1, return the original number or symbol from the string array, otherwise return the letter from the alphabet array based on the calculated offset. For both of these expressions we use an integer index, allowing us to select the letter based on position generated by range(). The result of this action is an array of encrypted letters based on the calculated offsets.

## Decrypt

SelectOffsetDecrypt: is based on two expressions, from is based on the same range expression we’ve seen before and the map is **mod(add(Sub(26, body(‘SelectSecretSequence’)?[item()]), body(‘SelectStringSequence’)?[item()]), 26)**. Here we subtract the secret letter sequence index from 26 and add on the string letter sequence index before using mod to extract the remainder. This allows us to reverse the original encryption based on the calculated indexes.

SelectDecryptedLetters: is based on two expressions, from is, you guessed it, the same range expression to calculate those indexes and then map is similar to the encrypt, albeit using the indexes from the SelectOffsetDecrypt array **if(equals(body(‘SelectStringSequence’)?[item()], -1), outputs(‘ComposeStringArray’)?[item()], outputs(‘ComposeAlphabetArray’)?[body(‘SelectOffsetDecrypt’)?[item()]])**. The result of this action is an array of decrypted letters based on the calculated offsets.

Compose: because the logic could branch yes or no depending on if the user has selected encrypt or decrypt, we need to get the result from above that isn’t null. We can do this using a coalesce which returns the first non null value. The expression **join(coalesce (body(‘SelectEncryptedLetters’),body(‘SelectDecryptedLetters’)),”)** will first check for the first non null array from either encrypt or decrypt and then join the array of letters to form a newly encrypted or decrypted string.

Send an email: Based on the email addressed supplied to the form, I generate and send an email and append “ed” onto the word encrypt/decrypt to provide your new string.

Happy encrypting / decrypting! Some videos that cover some of these techniques can be watched below: