我试图重写rails activesupport解密到golang,但得到了这个错误

err aesGCMOpen got cipher: message authentication failed

以下是来自Active Support解密的Rails代码

class Crypton
  SECRET_KEY_BASE = ENV["SECRET_KEY_BASE"]
  class << self
    def encrypt text
        raise 'Encypt failed, secret_key_base not found' unless SECRET_KEY_BASE.present?
        text = text.to_s unless text.is_a? String
  
        len   = ActiveSupport::MessageEncryptor.key_len
        salt  = SecureRandom.hex len
        key   = ActiveSupport::KeyGenerator.new(SECRET_KEY_BASE).generate_key salt, len
        crypt = ActiveSupport::MessageEncryptor.new key
        encrypted_data = crypt.encrypt_and_sign text
        "#{salt}$$#{encrypted_data}"
    end
    def decrypt text
      raise 'Decrypt failed, secret_key_base not found' unless SECRET_KEY_BASE.present?
      salt, data = text.split "$$"

      len   = ActiveSupport::MessageEncryptor.key_len
      key   = ActiveSupport::KeyGenerator.new(SECRET_KEY_BASE).generate_key salt, len
      crypt = ActiveSupport::MessageEncryptor.new key
      crypt.decrypt_and_verify data
    end
  end
end

这是我的Golang代码,我try 从Rails解密活动重写支持

// DecryptGCM
// reference on Rails 5.2-stable:
// https://github.com/rails/rails/blob/5-2-stable/activesupport/lib/active_support/message_encryptor.rb#L183
func DecryptGCM(encryptedText string, secretKeyBase string) (string, error) {
    encryptText := strings.Split(encryptedText, "$$")
    saltHex := encryptText[0]
    encodedText := encryptText[1]

    splitEncodedText := strings.Split(encodedText, "--")
    encodedText = splitEncodedText[0]
    ivText := splitEncodedText[1]
    authTagText := splitEncodedText[2]

    decodeText, err := base64.StdEncoding.DecodeString(encodedText)
    if err != nil {
        return "", fmt.Errorf(`err b64 decode text got %v`, err)
    }

    ivDecodeText, err := base64.StdEncoding.DecodeString(ivText)
    if err != nil {
        return "", fmt.Errorf(`err b64 iv got %v`, err)
    }

    authTagTextDecoded, err := base64.StdEncoding.DecodeString(authTagText)
    if err != nil {
        return "", fmt.Errorf(`err b64 auth tag got %v`, err)
    }

    key := GenerateKey(secretKeyBase, saltHex)

    block, err := aes.NewCipher(key)
    if err != nil {
        return "", fmt.Errorf(`err aesNewCipher got %v`, err)
    }

    aesGCM, err := cipher.NewGCM(block)
    if err != nil {
        return "", fmt.Errorf(`err chipperNewGCM got %v`, err)
    }

    plaintext, err := aesGCM.Open(nil, ivDecodeText, decodeText, authTagTextDecoded)
    if err != nil {
        return "", fmt.Errorf(`err aesGCMOpen got %v`, err)
    }

    return string(plaintext), nil
}

func GenerateKey(secretKeyBase string, saltHex string) []byte {
    key := pbkdf2.Key([]byte(secretKeyBase), []byte(saltHex), 65536, 32, sha1.New)
    return key
}

func TestMain(t *testing.T) {
    encryptText := "7c7eb6202943398b0d0619d008d226372f1b3b341eb39500eab71c3b67b7f641$$hDJ5e+6QkoCjk4cqT+hAY9c7Jj7Hxg==--t9hrqWnzQeeJTffr--1bHoguSmIkYQrpI1cd/KRQ=="


    decrypted, err := DecryptGCM(encryptText, SECRET_KEY)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Decrypted:", decrypted)
    }
}

这里是关键:

SECRET_KEY_BASE="3ae9b0ce19316f877554a0427044180e27267fb9798db9147feeb318865b3a52f79824201608f6e4e10dc8e3f29e5bf4b83e46c4103ff8d98b99903d054d720i"

我通过这个rails命令生成了加密数据

Crypton.encrypt("hello, world")

如果您发现了任何解决方案,请留言,

谢谢

可以解密Rails加密中的加密数据

推荐答案

In the aesGCM.Open() call of the Go code, ciphertext and authentication tag are passed in the third and fourth parameters respectively. This is wrong. Both data must be concatenated and passed in the third parameter. The fourth parameter needs to be nil. This parameter is for the additional data that is not used here.
In addition, the deserialization of the decrypted data is missing in the Go code. For this, an appropriate library must be applied, e.g. ruby-marshal.

总的来说,需要作出以下改变:

import (
    "bytes"
    rbmarshal "github.com/dozen/ruby-marshal"
    ...
)

...

func DecryptGCM(encryptedText string, secretKeyBase string) (string, error) {
    
    ...
    
    plaintext, err := aesGCM.Open(nil, ivDecodeText, append(decodeText, authTagTextDecoded...), nil) // Fix 1
    if err != nil {
        return "", fmt.Errorf(`err aesGCMOpen got %v`, err)
    }

    var v string
    rbmarshal.NewDecoder(bytes.NewReader(plaintext)).Decode(&v) // Fix 2
    return string(v), nil
}

有了这些更改,用Rails代码加密的数据就可以用GO代码成功解密.

Ruby-on-rails相关问答推荐

未捕获语法错误:try 编辑TRIX时,请求的模块未在Rails 7.1中提供名为默认的导出(在youtube.js:1:8)

刺激中的Rails 7和 bootstrap 错误-无法解析模块说明符 bootstrap

如何在Rails中创建没有字符串的查询

SASS,Rails 7:找不到要导入的样式表

搜查升级到 4.0.0 和 ActionText::RichText

如何从 Rails7.2 中的控制器获取名称空间?

如何让删除链接响应 Rails 7 中的 turbo_stream 和 html?

如何使用 activerecord activerecord-session_store 在 Rails 应用程序中使用 cookie 值在数据库中查找会话记录

ArgumentError 用于 Ruby on Rails 中非常简单的初始化方法,没有参数

Rails 5:如何从数据库中删除列?

Rails 3 - Select 包含?

在 Nokogiri 中获取属性值以提取链接 URL

从控制器中删除 Cookie

如何在where子句中组合两个条件?

Ruby如何写入Tempfile

是否有与 PHP 的 isset() 等效的 Rails?

是否有不涉及删除 Gemfile.lock 的在任何源中找不到 *gem*错误的修复?

设计记住我和会话

rails 4 before_validation on: :create 或 on: :save

如何使用 url 连接到 postgresql