Ruby和JavaScript之间的MD5的不同值

时间:2015-07-05 18:30:51

标签: javascript ruby encoding cryptography md5

我需要能够在客户端JavaScript应用程序和Ruby服务器上的同一文件上运行MD5哈希。

目前我不能让两个哈希都相同。

在客户端上,我使用JQuery File Upload将文件上传到S3存储桶。我正在使用Crypto在回调中散列文件:

file =  data.files[0]
filename = file.name;
md5 = CryptoJS.MD5(CryptoJS.enc.Hex.parse(data.files[0].toString()));

这给了我: ee9cd5bf4272fc35bd57d184553bd25b

在Ruby中,它是一个模块Digest::MD5模块,由Gem用于散列:

Digest::MD5.file(file).to_s

这给了我: 4d51c9a4d3fd076489d6c96614ebce61

我无法控制Ruby方面,但为什么Crypto生成的校验和会有所不同?

请注意,我可以使用相同的API在本地测试:

path = 'path/to/file.jpg'
Digest::MD5.file(f).hexdigest
# 4d51c9a4d3fd076489d6c96614ebce61

该文件是一个大jpg(~1.8meg)

更新:为了回应@ kxyz的回答,使用不同编码器的加密js的结果是:

CryptoJS.MD5(CryptoJS.enc.Hex.parse(data.files[0].toString()));
// ee9cd5bf4272fc35bd57d184553bd25b

CryptoJS.MD5(CryptoJS.enc.Utf8.parse(data.files[0].toString()));
// 709d1d31dc47636e4f5ccbfd07601c19

CryptoJS.MD5(CryptoJS.enc.Latin1.parse(data.files[0].toString()));
// 709d1d31dc47636e4f5ccbfd07601c19

我还使用bash md5检查了从S3下载的复制文件的原始文件,该文件为两个文件生成了相同的哈希值:

4d51c9a4d3fd076489d6c96614ebce61 ,这与Ruby生成的哈希相同。

还使用online hasher检查哈希:

4d51c9a4d3fd076489d6c96614ebce61

3 个答案:

答案 0 :(得分:2)

您使用CryptoJS.enc.Latin1,而在Ruby中,您不需要定义编码Digest::MD5.file(file).to_s。请务必使用相同的编码。

尝试

Digest::MD5.hexdigest('foobar')

CryptoJS.MD5(CryptoJS.enc.Hex.parse('foobar'));

答案 1 :(得分:1)

data.files[0].toString()没有做你认为它正在做的事情。它只返回一个“[object File]”字符串而不是文件的内容。

您实际上需要读取文件,例如:

var reader = new FileReader();

reader.onload = function(e) {
    var contents = e.target.result;
    var hash = CryptoJS.MD5(contents);

    console.log(hash);
    console.log(hash.toString(CryptoJS.enc.Base64));
};

// Read in the image file as a data URL.
reader.readAsBinaryString(data.files[0]);

CryptoJS.MD5()的输出是本机CryptoJS二进制数组(WordArray)。以字符串形式打印时,默认情况下将其序列化为十六进制编码。如果您想要其他编码,则需要将其传递给toString()函数。

答案 2 :(得分:0)

我在使用uWSGI的网络主机上遇到了非常相似的问题。原来上传的文件数据有几个字符,导致md5不匹配,并且Rails在删除上传的文件后发出422响应。

如果您遇到相同的情况,这里是解决方法:

# app/controllers/upload_controller.rb <- Create this file
class UploadController < ActiveStorage::DiskController
  def update
    request.env['RAW_POST_DATA'] = request.body.read(request.content_length)
    super
  end
end

# config/routes.rb <- Edit this file
Rails.application.routes.draw do
  # [your routes]

  # Add the following two lines:
  # Fix IntegrityError caused by uWSGI upload
  put '/rails/active_storage/disk/:encoded_token', to: 'upload#update'
end

Original discussion (in French)在哪里找到修复程序。