Search code examples
lispcommon-lispironclad

why not ironclad:decrypt-in-place work as expected?


the code as follow:

(ql:quickload :ironclad)
(ql:quickload :crypto-shortcuts)

(use-package :ironclad)

(defparameter str "Hello World!")
(defparameter message (ascii-string-to-byte-array str))
(defparameter key "1234")

(let ((cipher (make-cipher :arcfour
                           :key (ascii-string-to-byte-array key)
                           :mode :stream
                           :initialization-vector (make-random-salt)))
      (text
       (ascii-string-to-byte-array
        (cryptos:to-base64 (copy-seq message)))))
  ;; #(83 71 86 115 98 71 56 103 86 50 57 121 98 71 81 104)
  (format t "~a~%" text)
  (encrypt-in-place cipher text)
  ;; #(86 14 39 220 145 171 63 106 89 41 57 41 135 32 85 188)
  ;; "Vg4n3JGrP2pZKTkphyBVvA=="
  (format t "~a~%" text)
  (format t "~a~%" (cryptos:to-base64 text))
  (decrypt-in-place cipher text)
  ;; ?
  ;; #(83 71 86 115 98 71 56 103 86 50 57 121 98 71 81 104)
  (format t "~a~%" text))

what's wrong with my code?

after (decrypt-in-place cipher text), text should be same as the original, but it doesn't. why?

can anyone help?

below is the crypto-shortcuts version:

(cryptos:decrypt (cryptos:encrypt str
                              key                                  
                              :cipher :arcfour
                              :mode :stream)
             key
             :cipher :arcfour
             :mode :stream)

everything is ok.


Solution

  • From my understanding, the algorithm of the cipher arcfour in Ironclad is cumulative: at each step of the algorithm, the internal result is changing.

    Here, you reuse the result of the encryption into the decryption. At that very moment, the internal state of the cipher is not initialized properly, its value is the result of the previous encryption.

    In order to work properly, the decryption cipher need to be initialized in the same way as the encryption cipher.

    The most easy way is to create 2 instances of cipher:

    (let* ((salt (make-random-salt))
           (cipher-encrypt (make-cipher :arcfour
                                        :key (ascii-string-to-byte-array key)
                                        :mode :stream
                                        :initialization-vector salt))
           (cipher-decrypt (make-cipher :arcfour
                                        :key (ascii-string-to-byte-array key)
                                        :mode :stream
                                        :initialization-vector salt))
           (text
            (ascii-string-to-byte-array
             (cryptos:to-base64 (copy-seq message)))))
      ;; #(83 71 86 115 98 71 56 103 86 50 57 121 98 71 81 104)
      (format t "~a~%" text)
      (encrypt-in-place cipher-encrypt text)
      ;; #(86 14 39 220 145 171 63 106 89 41 57 41 135 32 85 188)
      ;; "Vg4n3JGrP2pZKTkphyBVvA=="
      (format t "~a~%" text)
      (format t "~a~%" (cryptos:to-base64 text))
      (decrypt-in-place cipher-decrypt text)
      ;; ?
      ;; #(83 71 86 115 98 71 56 103 86 50 57 121 98 71 81 104)
      (format t "~a~%" text))
    #(83 71 86 115 98 71 56 103 86 50 57 121 98 71 81 104)
    #(86 14 39 220 145 171 63 106 89 41 57 41 135 32 85 188)
    Vg4n3JGrP2pZKTkphyBVvA==
    #(83 71 86 115 98 71 56 103 86 50 57 121 98 71 81 104)