it-swarm.com.de

Verschlüsselung mit AES-128 in Android und IPhone (anderes Ergebnis)

Ich versuche, Text mit dem AES-Algorithmus sowohl auf der Android- als auch auf der IPhone-Plattform zu verschlüsseln. Mein Problem ist, selbst wenn ich denselben Verschlüsselungs-/Entschlüsselungsalgorithmus (AES-128) und dieselben festen Variablen (Schlüssel, IV, Modus) verwende, erhalte ich auf beiden Plattformen unterschiedliche Ergebnisse. Ich füge Codebeispiele von beiden Plattformen ein, mit denen ich die Verschlüsselung/Entschlüsselung teste. Ich würde mich über eine Hilfe freuen, um festzustellen, was ich falsch mache.

  • Schlüssel: "123456789abcdefg"
  • IV: "1111111111111111"
  • Klartext: "HelloThere"
  • Modus: "AES/CBC/NoPadding"

Android-Code:

public class Crypto {
    private final static String HEX = "0123456789ABCDEF";

    public static String encrypt(String seed, String cleartext)
            throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = encrypt(rawKey, cleartext.getBytes());
        return toHex(result);
    }

    public static String decrypt(String seed, String encrypted)
            throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] enc = toByte(encrypted);
        byte[] result = decrypt(rawKey, enc);
        return new String(result);
    }

    private static byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("CBC");
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
        sr.setSeed(seed);
        kgen.init(128, sr); // 192 and 256 bits may not be available
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        return raw;
    }

    private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(clear);
        return encrypted;
    }

    private static byte[] decrypt(byte[] raw, byte[] encrypted)
            throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
    }

    public static String toHex(String txt) {
        return toHex(txt.getBytes());
    }

    public static String fromHex(String hex) {
        return new String(toByte(hex));
    }

    public static byte[] toByte(String hexString) {
        int len = hexString.length() / 2;
        byte[] result = new byte[len];
        for (int i = 0; i < len; i++)
            result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
                    16).byteValue();
        return result;
    }

    public static String toHex(byte[] buf) {
        if (buf == null)
            return "";

        StringBuffer result = new StringBuffer(2 * buf.length);
        for (int i = 0; i < buf.length; i++) {
            appendHex(result, buf[i]);
        }

        return result.toString();
    }

    private static void appendHex(StringBuffer sb, byte b) {
        sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
    }
}

IPhone (Ziel-C) Code:

- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData { 

    NSData* secretKey = [Cipher md5:cipherKey];

    CCCryptorRef cryptor = NULL;
    CCCryptorStatus status = kCCSuccess;

    uint8_t iv[kCCBlockSizeAES128];
    memset((void *) iv, 0x0, (size_t) sizeof(iv));

    status = CCCryptorCreate(encryptOrDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                         [secretKey bytes], kCCKeySizeAES128, iv, &cryptor);

    if (status != kCCSuccess) {
        return nil;
    }

    size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length], true);

    void * buf = malloc(bufsize * sizeof(uint8_t));
    memset(buf, 0x0, bufsize);

    size_t bufused = 0;
    size_t bytesTotal = 0;

    status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
                         buf, bufsize, &bufused);

    if (status != kCCSuccess) {
        free(buf);
        CCCryptorRelease(cryptor);
        return nil;
    }

    bytesTotal += bufused;

    status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);

    if (status != kCCSuccess) {
        free(buf);
        CCCryptorRelease(cryptor);
        return nil;
    }

    bytesTotal += bufused;

    CCCryptorRelease(cryptor);

    return [NSData dataWithBytesNoCopy:buf length:bytesTotal];
}

+ (NSData *) md5:(NSString *) stringToHash {

    const char *src = [stringToHash UTF8String];

    unsigned char result[CC_MD5_DIGEST_LENGTH];

    CC_MD5(src, strlen(src), result);

    return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}

Einige meiner Referenzen:

11
UBA_MobileTeam

Für das iPhone habe ich AESCrypt-ObjC verwendet und für Android diesen Code:

public class AESCrypt {

  private final Cipher cipher;
  private final SecretKeySpec key;
  private AlgorithmParameterSpec spec;


  public AESCrypt(String password) throws Exception
  {
    // hash password with SHA-256 and crop the output to 128-bit for key
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    digest.update(password.getBytes("UTF-8"));
    byte[] keyBytes = new byte[32];
    System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);

    cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
    key = new SecretKeySpec(keyBytes, "AES");
    spec = getIV();
  }       

  public AlgorithmParameterSpec getIV()
  {
    byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
    IvParameterSpec ivParameterSpec;
    ivParameterSpec = new IvParameterSpec(iv);

    return ivParameterSpec;
  }

  public String encrypt(String plainText) throws Exception
  {
    cipher.init(Cipher.ENCRYPT_MODE, key, spec);
    byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
    String encryptedText = new String(Base64.encode(encrypted, Base64.DEFAULT), "UTF-8");

    return encryptedText;
  }

  public String decrypt(String cryptedText) throws Exception
  {
    cipher.init(Cipher.DECRYPT_MODE, key, spec);
    byte[] bytes = Base64.decode(cryptedText, Base64.DEFAULT);
    byte[] decrypted = cipher.doFinal(bytes);
    String decryptedText = new String(decrypted, "UTF-8");

    return decryptedText;
  }
}
15
Dimentar

Es wundert mich nicht, dass Sie unterschiedliche Ergebnisse erzielen.

Ihr Problem ist, dass Sie einen SHA1PRNG für die Schlüsselableitung missbrauchen. AFAIK Es gibt keinen gemeinsamen Standard für die interne Arbeitsweise eines SHA1PRNG. AFAIR selbst die Implementierung von J2SE und Bouncycaste gibt unter Verwendung desselben Seeds unterschiedliche Ergebnisse aus.

Daher generiert Ihre Implementierung Ihrer getRawKey(byte[] seed) einen zufälligen Schlüssel. Wenn Sie den Schlüssel für die Verschlüsselung verwenden, erhalten Sie ein Ergebnis, das von diesem Schlüssel abhängt. Da der Schlüssel zufällig ist, erhalten Sie unter iOS nicht denselben Schlüssel und daher ein anderes Ergebnis.

Wenn Sie eine Schlüsselableitungsfunktion wünschen, verwenden Sie eine Funktion wie PBKDF2, die in Bezug auf die Schlüsselableitung nahezu vollständig standardisiert ist.

7
Robert

Unter Android verwenden Sie getBytes(). Dies ist ein Fehler, da Sie den Standardzeichensatz anstelle eines bekannten Zeichensatzes verwenden. Verwenden Sie stattdessen getBytes("UTF-8"), damit Sie genau wissen, welche Bytes Sie erhalten werden.

Ich kenne keine Entsprechung für Objective-C, verlasse mich aber nicht auf die Standardeinstellung. Geben Sie UTF-8 explizit an, wenn Sie Zeichenfolgen in Bytes konvertieren. Auf diese Weise erhalten Sie auf beiden Seiten die gleichen Bytes.

Ich stelle auch fest, dass Sie MD5 im Objective-C-Code, aber nicht im Android-Code verwenden. Ist das absichtlich?

3
rossum

Siehe meine Antwort für kennwortbasierte AES-Verschlüsselung, da Sie Ihren "Startwert" effektiv als Kennwort verwenden. (Ändern Sie einfach die Schlüssellänge von 256 auf 128, wenn Sie dies möchten.)

Es ist nicht zuverlässig, denselben Schlüssel zu generieren, indem Sie eine DRBG mit demselben Wert setzen.

Als nächstes verwenden Sie weder CBC noch IV für Ihre Android-Verschlüsselung. Mein Beispiel zeigt, wie man das auch richtig macht. Übrigens müssen Sie für jede Nachricht, die Sie verschlüsseln, eine neue IV generieren, wie in meinem Beispiel gezeigt, und diese zusammen mit dem Chiffretext senden. Ansonsten macht es keinen Sinn, CBC zu verwenden.

2
erickson

Wenn Sie ein Beispiel für kompatiblen Code für Android und iPhone wünschen, schauen Sie in die RNCryptor-Bibliothek für iOS und in die JNCryptor-Bibliothek für Java/Android.

Beide Projekte sind Open Source und haben ein gemeinsames Datenformat. In diesen Bibliotheken wird AES 256-Bit verwendet, es wäre jedoch trivial, den Code gegebenenfalls anzupassen, um 128-Bit-AES zu unterstützen.

Gemäß der akzeptierten Antwort verwenden beide Bibliotheken PBKDF2.

0
Duncan Jones