Saudações caros colegas do GUJ!
Estou curioso em saber: se há uma maneira simples de descobrir a senha de um documento *.odt?
Eu sei que ele usa o Algoritmo Blowfish CFB tem um salt e o checksum, tive toda esta informação pelo ficheiro [color=darkblue]manifest.xm[/color]l que se encontra na pasta META-INF:
<manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml" manifest:size="7563">
<manifest:encryption-data manifest:checksum-type="SHA1/1K" manifest:checksum="0G1aeeeshvXo9nPKuBM5sdygpAM=">
<manifest:algorithm manifest:algorithm-name="Blowfish CFB" manifest:initialisation-vector="Io3eDT0By/8="/>
<manifest:key-derivation manifest:key-derivation-name="PBKDF2" manifest:key-size="16" manifest:iteration-count="1024" manifest:salt="I9YJ+0490NuTXFRJ1fRM5A=="/>
Já tenho o seguinte codigo:
package mz.com.desafio;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Test {
private final static String SALT = "I9YJ+0490NuTXFRJ1fRM5A==";
private final static String VECTOR = "Io3eDT0By/8=";
private final static String CYPHER_TEXT = "0G1aeeeshvXo9nPKuBM5sdygpAM=";
private void unlock(String password)
{
// TODO Auto-generated method stub
MessageDigest digest;
try
{
digest = MessageDigest.getInstance("SHA-256");
digest.update( password.getBytes());
byte[] pwdHash = digest.digest();
byte[] dk = deriveKey( pwdHash, SALT.getBytes(Charset.forName("UTF-8")), 1024, 16 );
Key key = new SecretKeySpec( dk, "PBKDF2WithHmacSHA1");
IvParameterSpec iv = new IvParameterSpec(VECTOR.getBytes()); /** estou tendo problemas aqui nesta linha.**/
Cipher cipher = Cipher.getInstance( "Blowfish/CFB/NoPadding" ); // ?AES/CBC/NoPadding?
cipher.init( Cipher.DECRYPT_MODE, key, iv );
byte[] deflatedPlainText = cipher.doFinal(CYPHER_TEXT.getBytes());
ByteArrayInputStream iStream = new ByteArrayInputStream( deflatedPlainText );
InflaterInputStream inflater = new InflaterInputStream( iStream, new Inflater(true) );
ByteArrayOutputStream oStream = new ByteArrayOutputStream(20);
int inBuffer;
while( (inBuffer = inflater.read(deflatedPlainText)) >= 0 )
{
oStream.write( deflatedPlainText, 0, inBuffer );
}
byte[] plainText = oStream.toByteArray();
System.out.print(plainText);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
byte[] deriveKey( byte[] password,
byte[] salt,
int iterationCount,
int dkLen )throws NoSuchAlgorithmException, InvalidKeyException {
SecretKeySpec keyspec = new SecretKeySpec( password, "HmacSHA1" );
Mac prf = Mac.getInstance( "HmacSHA1" );
prf.init( keyspec );
// Note: hLen, dkLen, l, r, T, F, etc. are horrible names for
// variables and functions in this day and age, but they
// reflect the terse symbols used in RFC 2898 to describe
// the PBKDF2 algorithm, which improves validation of the
// code vs. the RFC:
int hLen = prf.getMacLength(); // 20 for SHA1
int l = ceil( dkLen, hLen); // 1 for 128bit (16-byte) keys
int r = dkLen - (l-1)*hLen; // 16 for 128bit (16-byte) keys
byte T[] = new byte[l * hLen];
int ti_offset = 0;
for (int i = 1; i <= l; i++)
{
F( T, ti_offset, prf, salt, iterationCount, i );
ti_offset += hLen;
}
if (r < hLen)
{
// Incomplete last block
byte DK[] = new byte[dkLen];
System.arraycopy(T, 0, DK, 0, dkLen);
return DK;
}
return T;
}
protected int ceil(int a, int b)
{
int m = 0;
if (a % b > 0)
{
m = 1;
}
return a / b + m;
}
private static void F( byte[] dest,
int offset,
Mac prf,
byte[] S,
int c,
int blockIndex ) {
final int hLen = prf.getMacLength();
byte U_r[] = new byte[ hLen ];
// U0 = S || INT (i);
byte U_i[] = new byte[S.length + 4];
System.arraycopy( S, 0, U_i, 0, S.length );
INT( U_i, S.length, blockIndex );
for( int i = 0; i < c; i++ )
{
U_i = prf.doFinal( U_i );
xor( U_r, U_i );
}
System.arraycopy(U_r, 0, dest, offset, hLen);
}
private static void xor( byte[] dest, byte[] src )
{
for( int i = 0; i < dest.length; i++ )
{
dest[i] ^= src[i];
}
}
private static void INT( byte[] dest,
int offset,
int i )
{
dest[offset + 0] = (byte) (i / (256 * 256 * 256));
dest[offset + 1] = (byte) (i / (256 * 256));
dest[offset + 2] = (byte) (i / (256));
dest[offset + 3] = (byte) (i);
}
public static void main(String[] args) {
Test t = new Test();
t.unlock("0G1aeeeshvXo9nPKuBM5sdygpAM=");
}
}
quem souber de alguma outra forma, por favor me informe.
Obrigado e desculpem por qualquer erro.