DEV Community

Rez Moss
Rez Moss

Posted on

Public-Key Cryptography: The Digital Handshake, Go Crypto 5

Hey there, crypto explorer! Ready to dive into the fascinating world of public-key cryptography? Think of it as the digital equivalent of a secret handshake that you can do in public. Sounds impossible? Let's break it down and see how Go helps us pull off this cryptographic magic trick!

RSA: The Granddaddy of Public-Key Crypto

First up, we've got RSA (Rivest-Shamir-Adleman). It's like the wise old grandfather of public-key systems - been around for ages and still going strong.

RSA Key Generation: Your Digital Identity

Let's start by creating our RSA keys:

import (
    "crypto/rand"
    "crypto/rsa"
    "fmt"
)

func main() {
    // Let's make a 2048-bit key. It's like choosing a really long password!
    privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        panic("Oops! Our key generator is feeling shy today.")
    }

    publicKey := &privateKey.PublicKey

    fmt.Println("Tada! We've got our keys. Keep the private one secret!")
    fmt.Printf("Private Key: %v\n", privateKey)
    fmt.Printf("Public Key: %v\n", publicKey)
}
Enter fullscreen mode Exit fullscreen mode

RSA Encryption and Decryption: Passing Secret Notes

Now, let's use these keys to send a secret message:

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "fmt"
)

func main() {
    privateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
    publicKey := &privateKey.PublicKey

    secretMessage := []byte("RSA is like a magic envelope!")

    // Encryption - Sealing our magic envelope
    ciphertext, err := rsa.EncryptOAEP(
        sha256.New(),
        rand.Reader,
        publicKey,
        secretMessage,
        nil,
    )
    if err != nil {
        panic("Our magic envelope got stuck!")
    }

    fmt.Printf("Our secret message, encrypted: %x\n", ciphertext)

    // Decryption - Opening our magic envelope
    plaintext, err := rsa.DecryptOAEP(
        sha256.New(),
        rand.Reader,
        privateKey,
        ciphertext,
        nil,
    )
    if err != nil {
        panic("Uh-oh, we can't open our own envelope!")
    }

    fmt.Printf("Decrypted message: %s\n", plaintext)
}
Enter fullscreen mode Exit fullscreen mode

RSA Signing and Verification: Your Digital Signature

RSA isn't just for secret messages. It can also create digital signatures:

import (
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "fmt"
)

func main() {
    privateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
    publicKey := &privateKey.PublicKey

    message := []byte("I solemnly swear that I am up to no good.")
    hash := sha256.Sum256(message)

    // Signing - Like signing a digital contract
    signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hash[:])
    if err != nil {
        panic("Our digital pen ran out of ink!")
    }

    fmt.Printf("Our digital signature: %x\n", signature)

    // Verification - Checking if the signature is genuine
    err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hash[:], signature)
    if err != nil {
        fmt.Println("Uh-oh, this signature looks fishy!")
    } else {
        fmt.Println("Signature checks out. Mischief managed!")
    }
}
Enter fullscreen mode Exit fullscreen mode

Elliptic Curve Cryptography (ECC): The New Kid on the Block

Now, let's talk about ECC. It's like RSA's cooler, more efficient cousin. It offers similar security with smaller keys, which is great for mobile and IoT devices.

ECDSA Key Generation: Your Elliptic Identity

Let's create our ECC keys:

import (
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "fmt"
)

func main() {
    privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    if err != nil {
        panic("Our elliptic curve generator took a wrong turn!")
    }

    publicKey := &privateKey.PublicKey

    fmt.Println("Voila! Our elliptic curve keys are ready.")
    fmt.Printf("Private Key: %v\n", privateKey)
    fmt.Printf("Public Key: %v\n", publicKey)
}
Enter fullscreen mode Exit fullscreen mode

ECDSA Signing and Verification: Curvy Signatures

Now, let's sign something with our elliptic keys:

import (
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "crypto/sha256"
    "fmt"
)

func main() {
    privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    publicKey := &privateKey.PublicKey

    message := []byte("Elliptic curves are mathematically delicious!")
    hash := sha256.Sum256(message)

    // Signing - Like signing with a very curvy pen
    r, s, err := ecdsa.Sign(rand.Reader, privateKey, hash[:])
    if err != nil {
        panic("Our curvy signature got a bit too curvy!")
    }

    fmt.Printf("Our elliptic signature: (r=%x, s=%x)\n", r, s)

    // Verification - Checking if our curvy signature is legit
    valid := ecdsa.Verify(publicKey, hash[:], r, s)
    fmt.Printf("Is our curvy signature valid? %v\n", valid)
}
Enter fullscreen mode Exit fullscreen mode

Key Management: Keeping Your Digital Identity Safe

Now, let's talk about keeping these keys safe. It's like having a really important key to a really important door - you want to keep it secure!

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/pem"
    "fmt"
)

func main() {
    privateKey, _ := rsa.GenerateKey(rand.Reader, 2048)

    // Encoding our private key - Like putting it in a special envelope
    privateKeyBytes := x509.MarshalPKCS1PrivateKey(privateKey)
    privateKeyPEM := pem.EncodeToMemory(&pem.Block{
        Type:  "RSA PRIVATE KEY",
        Bytes: privateKeyBytes,
    })

    fmt.Printf("Our key in its special envelope:\n%s\n", privateKeyPEM)

    // Decoding our private key - Taking it out of the envelope
    block, _ := pem.Decode(privateKeyPEM)
    decodedPrivateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        panic("We forgot how to open our own envelope!")
    }

    fmt.Printf("Our key, safe and sound: %v\n", decodedPrivateKey)
}
Enter fullscreen mode Exit fullscreen mode

The Golden Rules of Public-Key Cryptography

Now that you're wielding these powerful crypto tools, here are some golden rules to keep in mind:

  1. Size matters: For RSA, go big or go home - at least 2048 bits. For ECC, 256 bits is the sweet spot.

  2. Randomness is your friend: Always use crypto/rand for key generation. Using weak randomness is like using "password123" as your key.

  3. Rotate your keys: Like changing your passwords, rotate your keys regularly.

  4. Standard formats are standard for a reason: Use PEM for storing and sending keys. It's like using a standard envelope - everyone knows how to handle it.

  5. Padding is not just for furniture: For RSA encryption, always use OAEP padding. It's like bubble wrap for your encrypted data.

  6. Hash before you sign: When signing large data, sign the hash, not the data itself. It's faster and just as secure.

  7. Performance matters: Public-key operations can be slow, especially RSA. Use them wisely.

What's Next?

Congratulations! You've just added public-key cryptography to your toolkit. These techniques are perfect for secure communication, digital signatures, and building trust in the wild west of the internet.

Next up, we'll dive deeper into digital signatures and their applications. It's like learning to write your name in a way that's impossible to forge - pretty cool, right?

Remember, in the world of cryptography, understanding these basics is crucial. It's like learning the rules of the road before you start driving. Master these, and you'll be well on your way to creating secure, robust applications in Go.

So, how about you try encrypting a message for a friend using their public key? Or maybe implement a simple digital signature system? The world of secure, authenticated communication is at your fingertips! Happy coding, crypto champion!

Top comments (0)