Vigenere Cipher in Swift UI HELP

Can someone help me to write a vigenere cipher in swift UI?
I’ve found some encryption methods but I can’t get any of them to work in Swift UI.
link1,Link2
I’m working on Chris’s chat application to pass the message through a vigenere encryption algorithm from text field and upload it to Firebase. Then download it from there and run it through the decryption algorithm to show the original text on ConversationView.

I thought of writing it as a helper method. Create a VigenereCipher file in the Helpers folder. Write the algorithm in it and call it when encrypting and decrypting.

Can anyone help me with this?

Hey! Thanks for the details/ links :slight_smile:

You probably already did this, but sometimes the obvious solution is the answer, so I’m going to ask… did you create this file Vigenere.swift in your project? Copy the code from here into that file, then you should be able to call it per the README’s instructions:

Hey, thanks for the answer!

For now, I’ll try to solve it with the second algorithm. This one here: Link

I created a VigenereCipher file in Helpers folder and I put this in:

Then I created two new functions in the ChatViewModel file for encrypt and decrypt.
Screenshot 2022-06-11 at 16.23.09

The encryption part already works as shown below.
Screenshot 2022-06-11 at 16.25.59

The decoding part is unfortunately not so easy, because getMessages does not return a String.

Any ideas how to solve it?

Nice work moving forward!

What does your Chat and ChatMessage classes look like? My assumption is that these classes contain a String attribute. Therefore, take that String attribute, and pass it into your decryption method. Because it only accepts Strings you need to convert it to a String.

By the way, use three tick marks, then paste your code in there, versus using screenshots for code examples. ``` insert code here, followed by three more ticks

1 Like

So far, the program works as follows.

We create a new VigenereCipher file in the Helpers folder:

import Foundation


public func convertToUnicodeScalars(
  str: String,
  minChar: UInt32,
  maxChar: UInt32
) -> [UInt32] {
  var scalars = [UInt32]()
 
  for scalar in str.unicodeScalars {
    let val = scalar.value
 
    guard val >= minChar && val <= maxChar else {
      continue
    }
 
    scalars.append(val)
  }
 
  return scalars
}
 
public struct Vigenere {
  private let keyScalars: [UInt32]
  private let smallestScalar: UInt32
  private let largestScalar: UInt32
  private let sizeAlphabet: UInt32
 
  public init?(key: String, smallestCharacter: Character = "A", largestCharacter:  Character = "Z") {
    let smallScalars = smallestCharacter.unicodeScalars
    let largeScalars = largestCharacter.unicodeScalars
 
    guard smallScalars.count == 1, largeScalars.count == 1 else {
      return nil
    }
 
    self.smallestScalar = smallScalars.first!.value
    self.largestScalar = largeScalars.first!.value
    self.sizeAlphabet = (largestScalar - smallestScalar) + 1
 
    let scalars = convertToUnicodeScalars(str: key, minChar: smallestScalar, maxChar: largestScalar)
 
    guard !scalars.isEmpty else {
      return nil
    }
 
    self.keyScalars = scalars
 
  }
 
  public func decrypt(_ str: String) -> String? {
    let txtBytes = convertToUnicodeScalars(str: str, minChar: smallestScalar, maxChar: largestScalar)
 
    guard !txtBytes.isEmpty else {
      return nil
    }
 
    var res = ""
 
    for (i, c) in txtBytes.enumerated() where c >= smallestScalar && c <= largestScalar {
      guard let char =
        UnicodeScalar((c &+ sizeAlphabet &- keyScalars[i % keyScalars.count]) % sizeAlphabet &+ smallestScalar)
      else {
        return nil
      }
 
      res += String(char)
    }
 
    return res
  }
 
  public func encrypt(_ str: String) -> String? {
    let txtBytes = convertToUnicodeScalars(str: str, minChar: smallestScalar, maxChar: largestScalar)
 
    guard !txtBytes.isEmpty else {
      return nil
    }
 
    var res = ""
 
    for (i, c) in txtBytes.enumerated() where c >= smallestScalar && c <= largestScalar {
      guard let char =
        UnicodeScalar((c &+ keyScalars[i % keyScalars.count] &- 2 &* smallestScalar) % sizeAlphabet &+ smallestScalar)
      else {
        return nil
      }
 
      res += String(char)
    }
 
    return res
  }
}

We create two new functions in the ChatViewModel file:

    func encryptMessage(msg: String, key: String) ->String {
        
        let cipher = Vigenere(key: key, smallestCharacter: " ", largestCharacter: "🛹")!
        return cipher.encrypt(msg)!
    }
    
    func decryptMessage(msg: String, key: String) ->String {
    
        let cipher = Vigenere(key: key, smallestCharacter: " ", largestCharacter: "🛹")!
        return cipher.decrypt(msg)!
    }
    
}

In the ChatViewModel file, a new key input parameter is added to the sendMessage function.
We perform the encryption process.

    func sendMessage(msg: String, key: String) {
        
        // Check that we have a selected chat
        guard selectedChat != nil else {
            return
        }
        
        // newly added code line -----
        let emsg = encryptMessage(msg: msg, key: key)
        // ------------------
        
        databaseService.sendMessage(msg: emsg, chat: selectedChat!)
        
    }

In the ConversationView File, we created a new chatKey variable to store the encryption key:

    @State var chatKey = " "

We have created a new TextField. Here we can enter the key we want to encrypt:

                    // Key field
                    ZStack {
                        
                        Rectangle()
                            .foregroundColor(Color("date-pill"))
                            .cornerRadius(50)
                                                   
                        TextField("Type your key", text: $chatKey)
                            .foregroundColor(Color("text-input"))
                            .font(Font.bodyParagraph)
                            .disableAutocorrection(true)
                            .textInputAutocapitalization(.never)
                            .padding(10)
                        
                    }
                    .frame(height: 44)

When we push send button clean up key text:

chatKey = chatKey.trimmingCharacters(in: .whitespacesAndNewlines)

We specify the new key parameter for encryption:

                                // Send message
                                chatViewModel.sendMessage(msg: chatMessage, key: chatKey)

— Decryption —
Decryption is performed in the ConversationView File:

                                        // Text Message
                                        let dmsg = chatViewModel.decryptMessage(msg: msg.msg, key: chatKey)
                                        
                                        // Determine if it's a group chat and a msg from another user
                                        if participants.count > 1 && !isFromUser {
                                            
                                            let userOfMsg = participants.filter { p in
                                                p.id == msg.senderid
                                            }.first
                                            
                                            // Show a text msg with name
                                            ConversationTextMessage(msg: dmsg,
                                                                    isFromUser: isFromUser,
                                                                    name: "\(userOfMsg?.firstname ?? "") \(userOfMsg?.lastname ?? "")")
                                        }
                                        else {
                                            // Text message with no name
                                            ConversationTextMessage(msg: dmsg,
                                                                    isFromUser: isFromUser)
                                        }

This is what messaging looks like.

There is a problem that the chatKey must have at least one character or the application freezes. By default, the key is a space. When the message is sent, the space is deleted and the text we write becomes the key. If you want to delete the key you have to leave a character in the text field. The text field cannot be empty.

As a workaround I thought about this but it throws an error:
Type ‘()’ cannot conform to ‘View’

                    // Key field
                    ZStack {
                        if chatKey == "" {
                            chatKey = " "
                        }

Any idea what the problem might be?
I can share the code if necessary.

Hey @chris1155 thanks for the further details! However, honestly, I’m confused what we’re troubleshooting now…

Was it to decode the message?

Also, I had asked about your Chat and ChatMessage structs/ classes, but don’t see those listed…