kopia lustrzana https://github.com/ryukoposting/Signal-Android
87 wiersze
2.7 KiB
Java
87 wiersze
2.7 KiB
Java
/**
|
|
* Copyright (C) 2013 Open Whisper Systems
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package org.whispersystems.textsecure.crypto.kdf;
|
|
|
|
import android.util.Log;
|
|
|
|
import org.whispersystems.textsecure.util.Conversions;
|
|
|
|
import java.security.MessageDigest;
|
|
import java.security.NoSuchAlgorithmException;
|
|
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
|
public class NKDF {
|
|
|
|
public static final int LEGACY_CIPHER_KEY_LENGTH = 16;
|
|
public static final int LEGACY_MAC_KEY_LENGTH = 20;
|
|
|
|
public DerivedSecrets deriveSecrets(byte[] sharedSecret, boolean isLowEnd)
|
|
{
|
|
SecretKeySpec cipherKey = deriveCipherSecret(isLowEnd, sharedSecret);
|
|
SecretKeySpec macKey = deriveMacSecret(cipherKey);
|
|
|
|
return new DerivedSecrets(cipherKey, macKey);
|
|
}
|
|
|
|
private SecretKeySpec deriveCipherSecret(boolean isLowEnd, byte[] sharedSecret) {
|
|
byte[] derivedBytes = deriveBytes(sharedSecret, LEGACY_CIPHER_KEY_LENGTH * 2);
|
|
byte[] cipherSecret = new byte[LEGACY_CIPHER_KEY_LENGTH];
|
|
|
|
if (isLowEnd) {
|
|
System.arraycopy(derivedBytes, LEGACY_CIPHER_KEY_LENGTH, cipherSecret, 0, LEGACY_CIPHER_KEY_LENGTH);
|
|
} else {
|
|
System.arraycopy(derivedBytes, 0, cipherSecret, 0, LEGACY_CIPHER_KEY_LENGTH);
|
|
}
|
|
|
|
return new SecretKeySpec(cipherSecret, "AES");
|
|
}
|
|
|
|
private SecretKeySpec deriveMacSecret(SecretKeySpec key) {
|
|
try {
|
|
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
|
byte[] secret = md.digest(key.getEncoded());
|
|
|
|
return new SecretKeySpec(secret, "HmacSHA1");
|
|
} catch (NoSuchAlgorithmException e) {
|
|
throw new IllegalArgumentException("SHA-1 Not Supported!",e);
|
|
}
|
|
}
|
|
|
|
private byte[] deriveBytes(byte[] seed, int bytesNeeded) {
|
|
MessageDigest md;
|
|
|
|
try {
|
|
md = MessageDigest.getInstance("SHA-256");
|
|
} catch (NoSuchAlgorithmException e) {
|
|
Log.w("NKDF", e);
|
|
throw new IllegalArgumentException("SHA-256 Not Supported!");
|
|
}
|
|
|
|
int rounds = bytesNeeded / md.getDigestLength();
|
|
|
|
for (int i=1;i<=rounds;i++) {
|
|
byte[] roundBytes = Conversions.intToByteArray(i);
|
|
md.update(roundBytes);
|
|
md.update(seed);
|
|
}
|
|
|
|
return md.digest();
|
|
}
|
|
}
|