I was trying to decode the JWT payload in java but this payload is compressed/deflated
"zip": "DEF"
java.util.zip.DataFormatException: incorrect header check
private static byte[] decompress(byte[] value) throws DataFormatException {
ByteArrayOutputStream bos = new ByteArrayOutputStream(value.length);
Inflater decompressor = new Inflater();
try {
decompressor.setInput(value);
final byte[] buf = new byte[1024];
while (!decompressor.finished()) {
int count = decompressor.inflate(buf);
bos.write(buf, 0, count);
}
} finally {
decompressor.end();
}
return bos.toByteArray();
}
public static void main(String[] args) throws Exception {
String payload = "7VPbjtMwEP2X4TUXO9CumjdYkFghoZVaFiHUB9eZNka-RLYTUVb5d8ZuKxW09AuQ8jL2mTPnHGeeYZLQPkM8Dgjtd-hjHEJb18EIH3sUOvaVFL4Lr6SbVMdXUNzAnIoyFTdxypjRql8iKmdhW4D02KGNSuj1uPuBMiZJ-175J_QhYVp4U7GKE2k6fTfaTmPCeAxu9BI3WT6cL4qzHZBOa2JLDAXQAH8kj8Q8av3FawJc-ltGgEvxAvEjSaV-Allh8EQijNLEB-vN280HujmoCW3K8OvHh_Wnb7CdydlOkfX3IiYSvlqxkr2mD-a5eFEGvy3j4Tq3AkIUcQzZpxk0RkypT0JKZfHedZlBuk7ZQ1YcjiGiIXh6GHqXXt9Vzh_qFGkdVFfL6ScRyNwJDbuDeTsXMJy9Zzl79GiTtuvoEgj93nmDPk8SMjqfGjoVBi1SSvdP68deeCPkkdxTMk7K0WeyFM9GmdPQhpdsWTZLEqJd_DyaXeIE_s_Imv-RnSJb_BUZS5ltZ8oNlCAtfNks2HLBOKe_eLf_80CFcHaZN1ZFXopBVXIKl8V15nqR64nXec3n3w";
byte[] byt = Base64.getUrlDecoder().decode(new String(payload).getBytes("UTF-8"));
byte[] b = decompress(byt);
String s = new String(b, StandardCharsets.UTF_8);
}
Some other folks in other programming language was able to crack this out using this, wondering how will I accomplish this in java?
const decompressedCard = zlib.inflateRawSync(decodedPayload);
const card = JSON.parse(decompressedCard.toString());
Ususally compressed payload is used in encrypted JWTs (JWE), but SMART Health Cards also use it in signed tokens (JWS). In both cases, the DEFLATE format as defined in RFC1951 is used. For Zlib (as shown in the example on the bottom of the question) you have to use deflateRaw/inflateRaw (DEFLATE without any Zlib or gz headers).
In case of the java.util.zip.Inflater, initializing the inflater with
Inflater decompressor = new Inflater(true);
is setting the nowrap parameter to true to decompress in raw mode (without header) data,
which is equal to using inflateRaw in Node.js.
(see also https://docs.oracle.com/javase/7/docs/api/java/util/zip/Inflater.html)
With this setting, the code in the question works fine and the given example data can be inflated to a JSON.
The thing about nowrap is correct I think, but nonetheless, I wasn't able to get your code working until I fixed the corrupt input (mentioned above) and did this:
import java.util.Base64;
import java.util.zip.GZIPInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class Decomp2 {
public static byte[] gunzip(byte[] value) throws IOException {
byte[] result = null;
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int numRead = -1;
try (GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(value))) {
while ((numRead = in.read(buf)) > -1) {
out.write(buf, 0, numRead);
}
result = out.toByteArray();
}
return result;
}
public static void main(String[] args) throws Exception {
// Data gzipped and b64url-encoded
String payload = "H4sIAKow-GAAA-1Ty27bMBC89zO2Vz1ItXZg3dokQIICRQC7CYrCB5paWwxIUSApoW6gf--StgG3SPwFAXRZcnZ2Zqh9gVFC_QJh3yPUv6ANofd1WXojXGhR6NAWUrjGf5R2VA1fQHYBcyjyWFzEKWOGTv0RQdkO1hlIhw12QQm9HDbPKEOUtG2Ve0TnI6aGzwUrOJHG069D12iMGIfeDk7iKsmH40V2tAPSak1skSEDGuD25JGYB61_OE2AU3_NCHAqXiF-IKnUT6BOGDyQCKM08cFy9WV1Szc7NWIXM3y6u19--wnriZxtFFm_ESGS8MWC5ewTfTBN2asy-GUZ9-e5ZeCDCINPPk2vMWBMfRRSqg6vbZMYpG1Ut0uK_d4HNASPD0Pv0uqrwrpdGSMtvWpKOf4mApk6oWJXMK2nDPqj9yRniw67qO08ughCt7XOoEuThAzWxYZG-V6LmNL14_KhFc4IuSf3lIyVcnCJLMazUuYwtOI5m-fVnIRoG74PZhM5gb8ZWfUe2SGy2X-RsZjZeqLcQAnSwufVjM1njHP6izfbfw-U90eXaWNV4LnoVSFHf1pca84XuRx5mdZ8-vAX5R6TWUMEAAA=";
byte[] byt = Base64.getUrlDecoder().decode(payload.getBytes("UTF-8"));
byte[] b = gunzip(byt);
String s = new String(b, StandardCharsets.UTF_8);
System.out.println(s);
}
}
Related
I was trying to decode the JWT payload in java but this payload is compressed/deflated
"zip": "DEF"
java.util.zip.DataFormatException: incorrect header check
private static byte[] decompress(byte[] value) throws DataFormatException {
ByteArrayOutputStream bos = new ByteArrayOutputStream(value.length);
Inflater decompressor = new Inflater();
try {
decompressor.setInput(value);
final byte[] buf = new byte[1024];
while (!decompressor.finished()) {
int count = decompressor.inflate(buf);
bos.write(buf, 0, count);
}
} finally {
decompressor.end();
}
return bos.toByteArray();
}
public static void main(String[] args) throws Exception {
String payload = "7VPbjtMwEP2X4TUXO9CumjdYkFghoZVaFiHUB9eZNka-RLYTUVb5d8ZuKxW09AuQ8jL2mTPnHGeeYZLQPkM8Dgjtd-hjHEJb18EIH3sUOvaVFL4Lr6SbVMdXUNzAnIoyFTdxypjRql8iKmdhW4D02KGNSuj1uPuBMiZJ-175J_QhYVp4U7GKE2k6fTfaTmPCeAxu9BI3WT6cL4qzHZBOa2JLDAXQAH8kj8Q8av3FawJc-ltGgEvxAvEjSaV-Allh8EQijNLEB-vN280HujmoCW3K8OvHh_Wnb7CdydlOkfX3IiYSvlqxkr2mD-a5eFEGvy3j4Tq3AkIUcQzZpxk0RkypT0JKZfHedZlBuk7ZQ1YcjiGiIXh6GHqXXt9Vzh_qFGkdVFfL6ScRyNwJDbuDeTsXMJy9Zzl79GiTtuvoEgj93nmDPk8SMjqfGjoVBi1SSvdP68deeCPkkdxTMk7K0WeyFM9GmdPQhpdsWTZLEqJd_DyaXeIE_s_Imv-RnSJb_BUZS5ltZ8oNlCAtfNks2HLBOKe_eLf_80CFcHaZN1ZFXopBVXIKl8V15nqR64nXec3n3w";
byte[] byt = Base64.getUrlDecoder().decode(new String(payload).getBytes("UTF-8"));
byte[] b = decompress(byt);
String s = new String(b, StandardCharsets.UTF_8);
}
Some other folks in other programming language was able to crack this out using this, wondering how will I accomplish this in java?
const decompressedCard = zlib.inflateRawSync(decodedPayload);
const card = JSON.parse(decompressedCard.toString());
Ususally compressed payload is used in encrypted JWTs (JWE), but SMART Health Cards also use it in signed tokens (JWS). In both cases, the DEFLATE format as defined in RFC1951 is used. For Zlib (as shown in the example on the bottom of the question) you have to use deflateRaw/inflateRaw (DEFLATE without any Zlib or gz headers).
In case of the java.util.zip.Inflater, initializing the inflater with
Inflater decompressor = new Inflater(true);
is setting the nowrap parameter to true to decompress in raw mode (without header) data,
which is equal to using inflateRaw in Node.js.
(see also https://docs.oracle.com/javase/7/docs/api/java/util/zip/Inflater.html)
With this setting, the code in the question works fine and the given example data can be inflated to a JSON.
The thing about nowrap is correct I think, but nonetheless, I wasn't able to get your code working until I fixed the corrupt input (mentioned above) and did this:
import java.util.Base64;
import java.util.zip.GZIPInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class Decomp2 {
public static byte[] gunzip(byte[] value) throws IOException {
byte[] result = null;
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int numRead = -1;
try (GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(value))) {
while ((numRead = in.read(buf)) > -1) {
out.write(buf, 0, numRead);
}
result = out.toByteArray();
}
return result;
}
public static void main(String[] args) throws Exception {
// Data gzipped and b64url-encoded
String payload = "H4sIAKow-GAAA-1Ty27bMBC89zO2Vz1ItXZg3dokQIICRQC7CYrCB5paWwxIUSApoW6gf--StgG3SPwFAXRZcnZ2Zqh9gVFC_QJh3yPUv6ANofd1WXojXGhR6NAWUrjGf5R2VA1fQHYBcyjyWFzEKWOGTv0RQdkO1hlIhw12QQm9HDbPKEOUtG2Ve0TnI6aGzwUrOJHG069D12iMGIfeDk7iKsmH40V2tAPSak1skSEDGuD25JGYB61_OE2AU3_NCHAqXiF-IKnUT6BOGDyQCKM08cFy9WV1Szc7NWIXM3y6u19--wnriZxtFFm_ESGS8MWC5ewTfTBN2asy-GUZ9-e5ZeCDCINPPk2vMWBMfRRSqg6vbZMYpG1Ut0uK_d4HNASPD0Pv0uqrwrpdGSMtvWpKOf4mApk6oWJXMK2nDPqj9yRniw67qO08ughCt7XOoEuThAzWxYZG-V6LmNL14_KhFc4IuSf3lIyVcnCJLMazUuYwtOI5m-fVnIRoG74PZhM5gb8ZWfUe2SGy2X-RsZjZeqLcQAnSwufVjM1njHP6izfbfw-U90eXaWNV4LnoVSFHf1pca84XuRx5mdZ8-vAX5R6TWUMEAAA=";
byte[] byt = Base64.getUrlDecoder().decode(payload.getBytes("UTF-8"));
byte[] b = gunzip(byt);
String s = new String(b, StandardCharsets.UTF_8);
System.out.println(s);
}
}
Desired:
Create compress and uncompress a string or byte array.
After that I plan to Base64 encode it for writing to a log file.
Unfortunately, it looks like it is not recognizing it as being compressed or something.
I'm assuming that it is missing some metadata bytes, but couldn't find what i needed.
Output:
Test Class:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.apache.commons.codec.binary.Base64;
public class TestEncodeDecode {
private static final String UTF_8 = "UTF-8";
public static void main(String[] args) throws IOException {
String originalString = " This online sample demonstrates functionality of a base64 property, ByteArray class and Huge asp file upload.\n The sample uses a special Base64 algorithm written for the ByteArray class.";
System.out.println(originalString);
System.out.println("------------------------------------------------------");
String compressedString = compressString(originalString);
System.out.println(compressedString);
System.out.println("------------------------------------------------------");
String uncompressedString = uncompressString(compressedString);
System.out.println(uncompressedString);
Validate.isTrue(originalString.equals(uncompressedString));
}
public static String compressString(String str) throws IOException {
if (str == null || str.length() == 0) {
return str;
}
byte[] bytes = str.getBytes(UTF_8);
ByteArrayOutputStream out = new ByteArrayOutputStream(bytes.length);
GZIPOutputStream gzip = new GZIPOutputStream(out);
gzip.write(bytes);
gzip.flush();
gzip.close(); //Finalizes the ByteArrayOutputStream's value
String compressedString = out.toString(UTF_8);
return compressedString;
}
public static String uncompressString(String str) throws IOException {
if (str == null || str.length() == 0) {
return str;
}
ByteArrayInputStream in = new ByteArrayInputStream(str.getBytes(UTF_8));
GZIPInputStream gzip = new GZIPInputStream(in);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] b = new byte[1000];
int len;
while ((len = in.read(b)) > 0) {
out.write(b, 0, len);
}
gzip.close();
out.close();
String uncompressedString = out.toString(UTF_8);
return uncompressedString;
}
}
I was trying to decrypt Whatsapp database file (msgstore.db.crypt) with java.
I found some python code and tried to do same thing with java. Probably its not that hard thing to do but I had some problems with handling decryption key.
But finally did it. So I wanted to share the code for people who need it.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class Crypto {
public FileInputStream mIn;
public FileOutputStream mOut;
public Crypto(String fileIn, String fileOut) {
try {
mIn = new FileInputStream(new File(fileIn));
mOut = new FileOutputStream(new File(fileOut));
decryptAES(mIn, mOut);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void decryptAES(InputStream in, FileOutputStream out) throws Exception {
final String string = "346a23652a46392b4d73257c67317e352e3372482177652c";
byte[] hexAsBytes = DatatypeConverter.parseHexBinary(string);
SecretKeySpec keySpec = new SecretKeySpec(hexAsBytes, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
in = new CipherInputStream(in, cipher);
byte[] buffer = new byte[24];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1)
{
out.write(buffer, 0, bytesRead);
}
}
public static void main(String[] args){
Crypto c = new Crypto("C:\\msgstore.db.crypt", "D:\\WhatsappDb");
System.out.println("Decrypting Done");
}
}
An updated answer for .crypt12 files:
These are compressed, and then encrypted using AES in GCM mode
Here is some python code showing how:
"""
Example how to decrypt whatsapp msgstore backups with extension .crypt12.
Author: Willem Hengeveld <itsme#xs4all.nl>
"""
from Crypto.Cipher import AES
import zlib
import sys
datafile = keyfile = None
if len(sys.argv)==1:
print("Usage: decrypt12.py <keyfile> <msgstore.db.crypt12>")
print(" the key file is commonly found in /data/data/com.whatsapp/files/key")
print(" the crypt file is commonly found in the directory: /data/media/0/WhatsApp/Databases/")
exit(1)
for arg in sys.argv[1:]:
if arg.find('crypt12')>0:
datafile = arg
elif arg.find('key')>0:
keyfile = arg
else:
print("unknown arg", arg)
with open(keyfile, "rb") as fh:
keydata = fh.read()
key = keydata[126:]
with open(datafile, "rb") as fh:
filedata = fh.read()
iv = filedata[51:67]
aes = AES.new(key, mode=AES.MODE_GCM, nonce=iv)
with open("msg-decrypted.db", "wb") as fh:
fh.write(zlib.decompress(aes.decrypt(filedata[67:-20])))
here is an pure java routine for .db.crypt12 without bouncycastle, but only JDK.
public class Crypt12 {
public static void main(final String[] args) {
final String c12File = "1/msgstore.db.crypt12"; // input file
final String decryptedDbFile = "1/msgstore.db"; // sqlite3 db output file
final String keyFile = "1/key";
try {
final byte[] key; try(FileInputStream s = new FileInputStream(keyFile)) { key = s.readAllBytes(); }
final byte[] buf; try(FileInputStream s = new FileInputStream(c12File)) { buf = s.readAllBytes(); }
if(!Arrays.equals(key, 27, 78, buf, 0, 51)) { System.out.println("Wrong Key-File"); return; }
final int available = buf.length - 67 - 20; // 67 Byte Header + 20 byte footer
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
final GCMParameterSpec iv = new GCMParameterSpec(128, buf, 51, 16);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, 126, 32, "AES"), iv);
final int zipLen = cipher.doFinal(buf, 67, available, buf, 0);
final Inflater unzip = new Inflater(false);
try(FileOutputStream s = new FileOutputStream(decryptedDbFile)) {
unzip.setInput(buf, 0, zipLen);
final byte[] b = new byte[1024];
while(!unzip.needsInput()) {
final int l = unzip.inflate(b, 0, b.length);
if(l > 0) s.write(b, 0, l);
}
}
} catch (final Exception e) {
e.printStackTrace(System.out);
}
}
}
this afternoon I wrote this class whose aim is give a easy way to exchange send a file over TCP Socket.
The problem it that, despite the final file size is correct, the content in wrong: precisely the destination file is made of various copies of the first buffer sent over Socket.
My class is simple: it calculates Q and R based on buffer size and sends this number together original filename to the client. I used a byte array to send data over Socket.
package it.s4sytems.java;
import java.io.*;
import java.net.*;
public class FileOverObjectStream
{
private File file;
private int bufferSize = 4*1024*1024; //4MB default, comunque รจ stabilito dal sender
private static class Info implements Serializable
{
public String fileName;
public long q;
public int r;
public int bufferSize;
}
public FileOverObjectStream(File file)
{
this.file = file;
}
public FileOverObjectStream(File file, int bufferSize)
{
this(file);
this.bufferSize = bufferSize;
}
public void sendFile(Socket socket) throws IOException
{
socket.getInputStream();
sendFile( socket.getOutputStream() );
}
public void sendFile(OutputStream outStream)throws IOException
{
sendFile( new ObjectOutputStream(outStream) );
}
public void sendFile(ObjectOutputStream objOutStream) throws IOException
{
BufferedInputStream in = new BufferedInputStream( new FileInputStream(file) );
byte[] buffer = new byte[bufferSize];
Info info = new Info();
info.fileName = file.getName();
info.bufferSize = bufferSize;
info.q = file.length() / bufferSize;
info.r = (int) file.length() % bufferSize;
objOutStream.writeObject(info);
for(long i=0; i<info.q; i++)
{
in.read(buffer);
objOutStream.writeObject(buffer);
objOutStream.flush();
}
in.read( buffer = new byte[info.r]);
objOutStream.writeObject(buffer);
objOutStream.flush();
in.close();
}
public String receiveFile(Socket socket) throws IOException, ClassNotFoundException
{
socket.getOutputStream();
return receiveFile( socket.getInputStream() );
}
public String receiveFile(InputStream inStream) throws IOException, ClassNotFoundException
{
return receiveFile( new ObjectInputStream(inStream) );
}
public String receiveFile(ObjectInputStream objInStream) throws IOException, ClassNotFoundException
{
BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(file) );
Info info = (Info) objInStream.readObject();
for(long i=0; i<info.q+1; i++)
{
byte[] buffer = (byte[]) objInStream.readObject();
out.write( buffer );
}
out.close();
return info.fileName;
}
}
I created two classes to make some try...
import it.s4sytems.java.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server
{
public static void main(String arg[]) throws IOException
{
ServerSocket ss = new ServerSocket(18000);
while(true)
{
Socket s = ss.accept();
File file = new File("G:\\HCHCK_72_5.38.part04.rar");
FileOverObjectStream sender = new FileOverObjectStream(file);
sender.sendFile(s);
s.close();
}
}
}
and client...
import it.s4sytems.java.*;
import java.io.*;
import java.net.*;
public class Client
{
public static void main(String arg[]) throws IOException, ClassNotFoundException
{
Socket s = new Socket("localhost", 18000);
String matricola = "616002424";
File directory = new File(System.getProperty("user.dir") + "\\" + matricola);
directory.mkdir();
File file = File.createTempFile("7897_", null, directory);
String originalName = new FileOverObjectStream(file).receiveFile(s);
System.out.println(originalName);
s.close();
File file2 = new File(directory, originalName);
System.out.println( file.renameTo( file2 ) );
System.out.println( file.getAbsoluteFile());
System.out.println( file2.getAbsoluteFile());
}
}
Probably it's a stupid thing, but I can't see it, so I need your help, please.
Thank you
I don't think ObjectOutputStream is suitable in your use case. Unless I missed something. In general, try to use some good library for IO such as Apache Commons IO. It has methods that would always do the right thing. Look at IOUtils for example.
Some errors to highlight (they would not happen with good library)
in.read(buffer) is not guaranteed to read exact number of bytes. You must check its result and only write correct number.
You write buffer object to ObjectOutputStream with writeObject. That writes serialized byte buffer not raw sequence of bytes.
Your ObjectInput/OutputStream code is flawed in all the ways Alex noted. I wouldn't use it at all, I would just use raw I/O. The canonical way to copy a stream in Java is as follows:
int count;
byte[] buffer = new byte[8192]; // or more, but megabytes is pointless as the network will packetize anyway
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Use that same code when both sending and receiving the file. If you want to send > 1 file per connection, you need to prefix all that by sending the file name and length, which you can do with DataOutputStream.writeUTF()/writeLong(), and DataInputStream.readUTF()/readLong() at the receiver, and modify the loop control to read exactly that many bytes:
long remaining = size; // the file size read from the network
while ((count = in.read(buffer, 0, remaining > buffer.length ? buffer.length : (int)remaining)) > 0)
{
out.write(buffer, 0, count);
remaining -= count;
}
I have a byte array wich i wish to add as an attachement to an email i am sending.
Unfortunally i can't find how to attach it as a byte array, the solution i have uses disk files (which i dont want since i dont want to write the byte array just so i can attach it).
I've found one solution that involves creating an object that extends DataSource and use this as a wrapper for the byte array and then feed that to the MimeBodyPart.
Anyone know of a better solution?
Creating a DataSource is the right approach. You don't have to write your own, though. Just use the ByteArrayDataSource from JavaMail.
Here is the code for your requirement...store attachment file as BLOB in DB and fetch that for sending it as a attachment in mail...............
import java.io.*;
import java.util.*;
import javax.activation.*;
public class BufferedDataSource implements DataSource {
private byte[] _data;
private java.lang.String _name;
public BufferedDataSource(byte[] data, String name) {
_data = data;
_name = name;
}
public String getContentType() { return "application/octet-stream";}
public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(_data);}
public String getName() { return _name;}
/**
* Returns an OutputStream from the DataSource
* #returns OutputStream Array of bytes converted into an OutputStream
*/
public OutputStream getOutputStream() throws IOException {
OutputStream out = new ByteArrayOutputStream();
out.write(_data);
return out;
}
}
===========================================================
//Getting ByteArray From BLOB
byte[] bytearray;
BLOB blob = ((OracleResultSet) rs).getBLOB("IMAGE_GIF");
if (blob != null) {
BufferedInputStream bis = new BufferedInputStream(blob.getBinaryStream());
ByteArrayOutputStream bao = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int length = 0;
while ((length = bis.read(buffer)) != -1) {
bao.write(buffer, 0, length);
}
bao.close();
bis.close();
bytearray = bao.toByteArray();
}
===============================================================
//Attach File for mail
MimeBodyPart att = new MimeBodyPart();
BufferedDataSource bds = new BufferedDataSource(bytearray, "AttName");
att.setDataHandler(new DataHandler(bds));
att.setFileName(bds.getName());