Skip to content

Commit

Permalink
Merge pull request #1 from metrico/decrypt
Browse files Browse the repository at this point in the history
Decrypt
  • Loading branch information
lmangani authored Sep 29, 2024
2 parents 269e272 + 8d9d00d commit ebd725d
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 13 deletions.
45 changes: 41 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ Store and Retrieve data from `pastila` in Go for fun a profit-loss
```go
import ("github.com/metrico/pasticca/paste")
```

## Example
See `main.go`

#### Plaintext/JSON
```go
// Example: Save some content
content := "This is a test paste."
Expand All @@ -22,12 +27,44 @@ if err != nil {
}
fmt.Printf("Loaded content: %s\nIs encrypted: %v\n", loadedContent, isEncrypted)
```

## Example
See `main.go`

```
Saved paste with fingerprint/hash: 913ae2b1/748ab86a806c2de1fd5753fb3ffff516
Loaded content: This is a test paste.
Is encrypted: false
```

#### Encrypted
```go
// Example: Save encrypted content
encryptedContent := "This is a secret message."
encryptedFingerprint, encryptedHashWithAnchor, err := paste.Save(encryptedContent, "", "", true)
if err != nil {
log.Fatalf("Error saving encrypted paste: %v", err)
}
fmt.Printf("Saved encrypted paste with fingerprint/hash: %s/%s\n", encryptedFingerprint, encryptedHashWithAnchor)

// Artificial Delay
time.Sleep(1 * time.Second)

// Example: Load and decrypt the encrypted content
decryptedContent, isStillEncrypted, err := paste.Load(encryptedFingerprint, encryptedHashWithAnchor)
if err != nil {
log.Fatalf("Error loading encrypted paste: %v", err)
}
fmt.Printf("Loaded and decrypted content: %s\nIs still encrypted: %v\n", decryptedContent, isStillEncrypted)

// Example: Try to load encrypted content without the key
encryptedHashWithoutAnchor := strings.Split(encryptedHashWithAnchor, "#")[0]
encryptedContentWithoutKey, isEncryptedWithoutKey, err := paste.Load(encryptedFingerprint, encryptedHashWithoutAnchor)
if err != nil {
log.Fatalf("Error loading encrypted paste without key: %v", err)
}
fmt.Printf("Loaded encrypted content without key: %s\nIs encrypted: %v\n", encryptedContentWithoutKey, isEncryptedWithoutKey)
```
```
Saved encrypted paste with fingerprint/hash: b4765c53/94cf5b7bee267b1d41c9ada746ebe6e1#FFUgNmg29LqBLdN3LQdfzw==
Loaded and decrypted content: This is a secret message.
Is still encrypted: true
Loaded encrypted content without key: T2ZudNTJcSKSCkod+eUeHp9LnupkOSBl6OlL6ts7Uss0LvrtPMoFrDI=
Is encrypted: true
```
61 changes: 52 additions & 9 deletions paste/paste.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"regexp"
"strings"
"fmt"
"io/ioutil"
)

const clickhouseURL = "https://play.clickhouse.com/?user=paste"
Expand All @@ -29,7 +28,14 @@ type DataResponse struct {
}

// Load retrieves data from Clickhouse
func Load(fingerprint, hash string) (string, bool, error) {
func Load(fingerprint, hashWithAnchor string) (string, bool, error) {
parts := strings.SplitN(hashWithAnchor, "#", 2)
hash := parts[0]
var key string
if len(parts) > 1 {
key = parts[1]
}

query := fmt.Sprintf(`
SELECT content, is_encrypted
FROM data
Expand All @@ -40,8 +46,6 @@ func Load(fingerprint, hash string) (string, bool, error) {
FORMAT JSON
`, fingerprint, hash)

// fmt.Printf("Debug: Executing query: %s\n", query) // Debug print

resp, err := http.Post(clickhouseURL, "application/x-www-form-urlencoded", strings.NewReader(query))
if err != nil {
return "", false, fmt.Errorf("HTTP request failed: %v", err)
Expand All @@ -52,13 +56,11 @@ func Load(fingerprint, hash string) (string, bool, error) {
return "", false, fmt.Errorf("HTTP status %s", resp.Status)
}

body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", false, fmt.Errorf("failed to read response body: %v", err)
}

// fmt.Printf("Debug: Response body: %s\n", string(body)) // Debug print

var response DataResponse
err = json.Unmarshal(body, &response)
if err != nil {
Expand All @@ -69,11 +71,52 @@ func Load(fingerprint, hash string) (string, bool, error) {
return "", false, fmt.Errorf("paste not found or multiple rows returned (rows: %d)", response.Rows)
}

// Convert uint8 to bool
content := response.Data[0].Content
isEncrypted := response.Data[0].IsEncrypted != 0

return response.Data[0].Content, isEncrypted, nil
if isEncrypted && key != "" {
decryptedContent, err := DecryptContent(content, key)
if err != nil {
return "", true, fmt.Errorf("failed to decrypt content: %v", err)
}
content = decryptedContent
}

return content, isEncrypted, nil
}

// DecryptContent decrypts the content using the provided key
func DecryptContent(encryptedContent, keyBase64 string) (string, error) {
key, err := base64.StdEncoding.DecodeString(keyBase64)
if err != nil {
return "", fmt.Errorf("failed to decode key: %v", err)
}

ciphertext, err := base64.StdEncoding.DecodeString(encryptedContent)
if err != nil {
return "", fmt.Errorf("failed to decode ciphertext: %v", err)
}

block, err := aes.NewCipher(key)
if err != nil {
return "", fmt.Errorf("failed to create cipher: %v", err)
}

if len(ciphertext) < aes.BlockSize {
return "", errors.New("ciphertext too short")
}

iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]

stream := cipher.NewCTR(block, iv)
plaintext := make([]byte, len(ciphertext))
stream.XORKeyStream(plaintext, ciphertext)

return string(plaintext), nil
}


// Save stores data in Clickhouse
func Save(content, prevFingerprint, prevHash string, isEncrypted bool) (string, string, error) {
text := content
Expand Down

0 comments on commit ebd725d

Please sign in to comment.