2011-07-25 28 views
15

Tengo un sitio que necesita encriptar y almacenar archivos binarios que se cargan en el servidor. La carga y almacenamiento funciona bien, pero estoy recibiendo este error al intentar escribir el archivo cifrado:Codificación :: UndefinedConversionError al escribir un archivo binario

Codificación :: UndefinedConversionError ("\ xDD" de ASCII-8BIT a UTF-8):

el código que hace que se parezca a esto:

fd_in = IO.sysopen(self[:name].tempfile.path, "rb")       
file_in = IO.open(fd_in)              
fd_out = IO.sysopen(self[:name].tempfile.path + ".encrypted", "wb")   
file_out = IO.open(fd_out)              
cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')       
cipher.encrypt                           
cipher.key = cipher_key              
cipher.iv = cipher_iv              
while chunk = file_in.read(1024)            
    file_out << cipher.update(chunk)            
end 
file_out << cipher.final 

la línea que hace que el error es el file_out < < cipher.update (fragmento) en el bucle while. Lo he analizado en línea y he encontrado algunos informes de problemas similares de conversión ASCII/UTF, pero todos parecen estar basados ​​en la coerción de entrada de cadena, no en la entrada de archivos continuos. Estoy usando Ruby 1.9.2, que creo que afecta la codificación de cadena por defecto.

Mi razonamiento sobre por qué (creo) Necesito usar un enfoque basado en flujo: los archivos tienden a ser grandes y no quiero cargar todo el archivo (entrada o salida) en la memoria para procesarlo.

Cualquier ayuda es apreciada. Gracias.

+0

que he encontrado que el uso de .force_encoding ("UTF-8") en los #update y #final llamadas resuelve el problema. Si alguien puede opinar sobre si esta es realmente la manera correcta de hacerlo y si (¿por qué?) UTF-8 es aceptable, me encantaría saberlo. –

+0

Por lo que vale, también revisé Encoding.default_external y Encoding.default_internal y ambos son UTF-8. –

Respuesta

27

Lo que quiere hacer cuando en/descifrar es tratar la entrada y salida como bytes sin procesar, quiere evitar cualquier transcodificación causada por la asociación de una codificación con sus datos a toda costa. Por lo tanto, debe abrir sus archivos en modo binario, tanto para leer como para escribir.

En realidad lo hizo, pero con IO # sysopen, pero luego no pasó las banderas "b" al usar IO # abrir.

Su código debería funcionar si en lugar de intentar esto:

fin = File.open("TODO", "rb")       
fout = File.open("TODO.encrypted", "wb")   
cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc') 
cipher.encrypt      
cipher.key = key              
cipher.iv = iv              
while chunk = fin.read(1024)            
    fout << cipher.update(chunk)            
end 
fout << cipher.final 
fin.close 
fout.close 
+0

Ah - Supuse (incorrectamente) que IO # open usaría el modo del descriptor de archivo de #sysopen. ¡Gracias! –

Cuestiones relacionadas