2

I'm trying to encrypt/decrypt some data in Go with RC4. I found that Go provides rc4 algorithm in crypto/rc4 package. I tried to encrypt/decrypt data using the package but ciphertext and decrypted plaintext is not what I expected.

I compared with RC4 online tool something like this but I'm sure Go's rc4 package has some problem. Because after I encrypt plaintext with Go rc4 and decrypt ciphertext decrypted plaintext' is not what I encrypted. Should I find other library?

The code what I run is this.

package main

import (
    "crypto/rc4"
    "fmt"
    "log"
)

func main() {
    c, err := rc4.NewCipher([]byte("dsadsad"))
    if err != nil {
        log.Fatalln(err)
    }
    src := []byte("asdsad")
    dst := make([]byte, len(src))
    fmt.Println("Plaintext: ", src)
    c.XORKeyStream(dst, src)
    c.XORKeyStream(src, dst)
    fmt.Println("Ciphertext: ", dst)
    fmt.Println("Plaintext': ", src)
}

And the output is this

Plaintext:  [97 115 100 115 97 100]
Ciphertext:  [98 41 227 117 93 79]
Plaintext':  [111 154 128 112 250 88]
icza
  • 389,944
  • 63
  • 907
  • 827
Pol4b
  • 51
  • 6
  • Who is submitting close vote with the reason as "Not reproducible or was caused by a typo"? How is the issue described in this post not reproducible for you? What typo do you see? The issue is clearly reproducible. Check here: https://play.golang.org/p/P1Pegmo_s19. Whoever is doing this is doing to multiple Go posts and such behavior is hostile to well-meaning Go beginners who are coming to forum for this help while doing their part of providing a [minimum, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – Lone Learner Aug 25 '20 at 13:45

2 Answers2

7

You can't use the same RC4 cipher to encrypt and then decrypt as it has internal state.

Construct a new cipher with the same key to decrypt:

// ENCRYPT
c, err := rc4.NewCipher([]byte("dsadsad"))
if err != nil {
    log.Fatalln(err)
}
src := []byte("asdsad")
fmt.Println("Plaintext: ", src)

dst := make([]byte, len(src))
c.XORKeyStream(dst, src)
fmt.Println("Ciphertext: ", dst)

// DECRYPT
c2, err := rc4.NewCipher([]byte("dsadsad"))
if err != nil {
    log.Fatalln(err)
}
src2 := make([]byte, len(dst))
c2.XORKeyStream(src2, dst)
fmt.Println("Plaintext': ", src2)

This will output (try it on the Go Playground):

Plaintext:  [97 115 100 115 97 100]
Ciphertext:  [98 41 227 117 93 79]
Plaintext':  [97 115 100 115 97 100]

But as the package doc states:

RC4 is cryptographically broken and should not be used for secure applications.

So use another, more secure algorithm such as crypto/aes.

icza
  • 389,944
  • 63
  • 907
  • 827
0
package main

import (
    "crypto/rc4"
    "flag"
    "fmt"
    "io"
    "log"
    "os"
)

var (
    key    = flag.String("k", "", "128-bit key to Encrypt/Decrypt.")
)

func main() {
    flag.Parse()

    if len(os.Args) < 2 || *key == "" {
        fmt.Println("Usage of", os.Args[0]+":")
        flag.PrintDefaults()
        os.Exit(1)
    }

    var err error
    ciph, _ := rc4.NewCipher([]byte(*key))
    buf := make([]byte, 64*1<<10)
    var n int
    for {
        n, err = os.Stdin.Read(buf)
        if err != nil && err != io.EOF {
            log.Fatal(err)
        }
        ciph.XORKeyStream(buf[:n], buf[:n])
        if _, err := os.Stdout.Write(buf[:n]); err != nil {
            log.Fatal(err)
        }
        if err == io.EOF {
            break
        }
    }
    os.Exit(0)
}

Theoretically OpenSSL compliant*

Don't use RC4 as encryption algorithm, just obfucator. Is broken. Good luck!