Issue with AES/DES RFC3211Wrap

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Issue with AES/DES RFC3211Wrap

MSKnete
Hi,
 
I have noticed that BC 1.60 changed the behavior of wrap ciphers in a way so that they can be also used in encrypt mode for wrapping data. This apparently works fine with AESWRAP and DESEDEWRAP. However when using AESRFC3211WRAP and DESEDERFC3211WRAP the wrapped data can't be unwrapped due to a javax.crypto.BadPaddingException. Please see the following class to demonstrate the issue:
 
import java.security.Key;
import java.security.Provider;
import java.util.Locale;
 
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
 
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
 
public class WrapTest {
 
  private static final Key KEY_AES128 = new SecretKeySpec(Hex.decode("c794a7735f469c59cf9d7ddd8c65201d"), "AES");
  private static final Key KEY_DES = new SecretKeySpec(Hex.decode("8ccbbc15340b46c7cee6e5b6d6b6bc3e08ea38b55d3e08d9"), "DES");
 
  private static final byte[] PLAIN = "abcdefgh".getBytes();
 
  private static Provider prov = new BouncyCastleProvider();
 
  public static void main(String[] args) throws Exception {
    String res = wrap("AESWRAP", KEY_AES128, PLAIN);
    unwrap("AESWRAP", KEY_AES128, Hex.decode(res));
    res = wrap("DESEDEWRAP", KEY_DES, PLAIN);
    unwrap("DESEDEWRAP", KEY_DES, Hex.decode(res));
 
    res = wrap("AESRFC3211WRAP", KEY_AES128, PLAIN);
    unwrap("AESRFC3211WRAP", KEY_AES128, Hex.decode(res));
    res = wrap("DESEDERFC3211WRAP", KEY_DES, PLAIN);
    unwrap("DESEDERFC3211WRAP", KEY_DES, Hex.decode(res));
  }
 
  private static String wrap(String algo, Key privKey, byte[] data) throws Exception {
    Cipher engine = Cipher.getInstance(algo, prov);
    engine.init(Cipher.ENCRYPT_MODE, privKey);
    String res = Hex.toHexString(engine.doFinal(data)).toUpperCase(Locale.ROOT);
    System.out.println(String.format("%s wrapped: %s", algo, res));
    return res;
  }
 
  private static String unwrap(String algo, Key privKey, byte[] data) throws Exception {
    Cipher engine = Cipher.getInstance(algo, prov);
    engine.init(Cipher.DECRYPT_MODE, privKey);
    String res = new String(engine.doFinal(data));
    System.out.println(String.format("%s unwrapped: %s", algo, res));
    return res;
  }
}
 
Is this an issue or have I just used the API wrong?
 
Kind Regards,
Michael Schäfer
Reply | Threaded
Open this post in threaded view
|

Re: Issue with AES/DES RFC3211Wrap

David Hook-3

The two variations require IVs, and generate them if one is not created, so if you try the following instead:

public class WrapTest {

  private static final Key KEY_AES128 = new SecretKeySpec(Hex.decode("c794a7735f469c59cf9d7ddd8c65201d"), "AES");
  private static final Key KEY_DES = new SecretKeySpec(Hex.decode("8ccbbc15340b46c7cee6e5b6d6b6bc3e08ea38b55d3e08d9"), "DES");

  private static final byte[] PLAIN = "abcdefgh".getBytes();

  private static Provider prov = new BouncyCastleProvider();

  public static void main(String[] args) throws Exception {
//    String res = wrap("AESWRAP", KEY_AES128, PLAIN);
//    unwrap("AESWRAP", KEY_AES128, Hex.decode(res));
//    res = wrap("DESEDEWRAP", KEY_DES, PLAIN);
//    unwrap("DESEDEWRAP", KEY_DES, Hex.decode(res));

    byte[][] res = wrap("AESRFC3211WRAP", KEY_AES128, PLAIN);
    unwrap("AESRFC3211WRAP", KEY_AES128, res);
    res = wrap("DESEDERFC3211WRAP", KEY_DES, PLAIN);
    unwrap("DESEDERFC3211WRAP", KEY_DES, res);
  }

  private static byte[][] wrap(String algo, Key privKey, byte[] data) throws Exception {
    Cipher engine = Cipher.getInstance(algo, prov);
    engine.init(Cipher.ENCRYPT_MODE, privKey);
    byte[] res = engine.doFinal(data);
    System.out.println(String.format("%s wrapped: %s", algo, Hex.toHexString(res)));
    return new byte[][] { engine.getIV(), res };
  }

  private static String unwrap(String algo, Key privKey, byte[][] data) throws Exception {
    Cipher engine = Cipher.getInstance(algo, prov);
    engine.init(Cipher.DECRYPT_MODE, privKey, new IvParameterSpec(data[0]));
    String res = new String(engine.doFinal(data[1]));
    System.out.println(String.format("%s unwrapped: %s", algo, res));
    return res;
  }
}

You should find it works. It raises an interesting point though - neither of these methods will work with data of more than 255 bytes, 
we should introduce a limit for these two. I'll have to add it to the list...

Regards,

David

On 13/09/18 19:31, [hidden email] wrote:
Hi,
 
I have noticed that BC 1.60 changed the behavior of wrap ciphers in a way so that they can be also used in encrypt mode for wrapping data. This apparently works fine with AESWRAP and DESEDEWRAP. However when using AESRFC3211WRAP and DESEDERFC3211WRAP the wrapped data can't be unwrapped due to a javax.crypto.BadPaddingException. Please see the following class to demonstrate the issue:
 
import java.security.Key;
import java.security.Provider;
import java.util.Locale;
 
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
 
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
 
public class WrapTest {
 
  private static final Key KEY_AES128 = new SecretKeySpec(Hex.decode("c794a7735f469c59cf9d7ddd8c65201d"), "AES");
  private static final Key KEY_DES = new SecretKeySpec(Hex.decode("8ccbbc15340b46c7cee6e5b6d6b6bc3e08ea38b55d3e08d9"), "DES");
 
  private static final byte[] PLAIN = "abcdefgh".getBytes();
 
  private static Provider prov = new BouncyCastleProvider();
 
  public static void main(String[] args) throws Exception {
    String res = wrap("AESWRAP", KEY_AES128, PLAIN);
    unwrap("AESWRAP", KEY_AES128, Hex.decode(res));
    res = wrap("DESEDEWRAP", KEY_DES, PLAIN);
    unwrap("DESEDEWRAP", KEY_DES, Hex.decode(res));
 
    res = wrap("AESRFC3211WRAP", KEY_AES128, PLAIN);
    unwrap("AESRFC3211WRAP", KEY_AES128, Hex.decode(res));
    res = wrap("DESEDERFC3211WRAP", KEY_DES, PLAIN);
    unwrap("DESEDERFC3211WRAP", KEY_DES, Hex.decode(res));
  }
 
  private static String wrap(String algo, Key privKey, byte[] data) throws Exception {
    Cipher engine = Cipher.getInstance(algo, prov);
    engine.init(Cipher.ENCRYPT_MODE, privKey);
    String res = Hex.toHexString(engine.doFinal(data)).toUpperCase(Locale.ROOT);
    System.out.println(String.format("%s wrapped: %s", algo, res));
    return res;
  }
 
  private static String unwrap(String algo, Key privKey, byte[] data) throws Exception {
    Cipher engine = Cipher.getInstance(algo, prov);
    engine.init(Cipher.DECRYPT_MODE, privKey);
    String res = new String(engine.doFinal(data));
    System.out.println(String.format("%s unwrapped: %s", algo, res));
    return res;
  }
}
 
Is this an issue or have I just used the API wrong?
 
Kind Regards,
Michael Schäfer


Reply | Threaded
Open this post in threaded view
|

RE: Issue with AES/DES RFC3211Wrap

Eckenfels. Bernd
Just in case somebody is as confused as me why there is a single byte IV. From Reading the wrapping definition in RFC3211: it is actually not a IV but a content length. The IV used in the double wrapping is extracted by the wrap itself. Not sure why this method doesn’t Hände the length byte like it handles the check bytes bit. It would be a compatible change to use the first byte if no IVSpec was given to make this less confusing to use...

Gruss
Bernd

--
http://www.seeburger.com
________________________________________
From: David Hook [[hidden email]]
Sent: Saturday, September 15, 2018 15:54
To: [hidden email]; [hidden email]
Subject: Re: [dev-crypto] Issue with AES/DES RFC3211Wrap

The two variations require IVs, and generate them if one is not created, so if you try the following instead:


public class WrapTest {

  private static final Key KEY_AES128 = new SecretKeySpec(Hex.decode("c794a7735f469c59cf9d7ddd8c65201d"), "AES");
  private static final Key KEY_DES = new SecretKeySpec(Hex.decode("8ccbbc15340b46c7cee6e5b6d6b6bc3e08ea38b55d3e08d9"), "DES");

  private static final byte[] PLAIN = "abcdefgh".getBytes();

  private static Provider prov = new BouncyCastleProvider();

  public static void main(String[] args) throws Exception {
//    String res = wrap("AESWRAP", KEY_AES128, PLAIN);
//    unwrap("AESWRAP", KEY_AES128, Hex.decode(res));
//    res = wrap("DESEDEWRAP", KEY_DES, PLAIN);
//    unwrap("DESEDEWRAP", KEY_DES, Hex.decode(res));

    byte[][] res = wrap("AESRFC3211WRAP", KEY_AES128, PLAIN);
    unwrap("AESRFC3211WRAP", KEY_AES128, res);
    res = wrap("DESEDERFC3211WRAP", KEY_DES, PLAIN);
    unwrap("DESEDERFC3211WRAP", KEY_DES, res);
  }

  private static byte[][] wrap(String algo, Key privKey, byte[] data) throws Exception {
    Cipher engine = Cipher.getInstance(algo, prov);
    engine.init(Cipher.ENCRYPT_MODE, privKey);
    byte[] res = engine.doFinal(data);
    System.out.println(String.format("%s wrapped: %s", algo, Hex.toHexString(res)));
    return new byte[][] { engine.getIV(), res };
  }

  private static String unwrap(String algo, Key privKey, byte[][] data) throws Exception {
    Cipher engine = Cipher.getInstance(algo, prov);
    engine.init(Cipher.DECRYPT_MODE, privKey, new IvParameterSpec(data[0]));
    String res = new String(engine.doFinal(data[1]));
    System.out.println(String.format("%s unwrapped: %s", algo, res));
    return res;
  }
}

You should find it works. It raises an interesting point though - neither of these methods will work with data of more than 255 bytes,
we should introduce a limit for these two. I'll have to add it to the list...

Regards,

David



On 13/09/18 19:31, [hidden email]<mailto:[hidden email]> wrote:
Hi,

I have noticed that BC 1.60 changed the behavior of wrap ciphers in a way so that they can be also used in encrypt mode for wrapping data. This apparently works fine with AESWRAP and DESEDEWRAP. However when using AESRFC3211WRAP and DESEDERFC3211WRAP the wrapped data can't be unwrapped due to a javax.crypto.BadPaddingException. Please see the following class to demonstrate the issue:

import java.security.Key;
import java.security.Provider;
import java.util.Locale;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

public class WrapTest {

  private static final Key KEY_AES128 = new SecretKeySpec(Hex.decode("c794a7735f469c59cf9d7ddd8c65201d"), "AES");
  private static final Key KEY_DES = new SecretKeySpec(Hex.decode("8ccbbc15340b46c7cee6e5b6d6b6bc3e08ea38b55d3e08d9"), "DES");

  private static final byte[] PLAIN = "abcdefgh".getBytes();

  private static Provider prov = new BouncyCastleProvider();

  public static void main(String[] args) throws Exception {
    String res = wrap("AESWRAP", KEY_AES128, PLAIN);
    unwrap("AESWRAP", KEY_AES128, Hex.decode(res));
    res = wrap("DESEDEWRAP", KEY_DES, PLAIN);
    unwrap("DESEDEWRAP", KEY_DES, Hex.decode(res));

    res = wrap("AESRFC3211WRAP", KEY_AES128, PLAIN);
    unwrap("AESRFC3211WRAP", KEY_AES128, Hex.decode(res));
    res = wrap("DESEDERFC3211WRAP", KEY_DES, PLAIN);
    unwrap("DESEDERFC3211WRAP", KEY_DES, Hex.decode(res));
  }

  private static String wrap(String algo, Key privKey, byte[] data) throws Exception {
    Cipher engine = Cipher.getInstance(algo, prov);
    engine.init(Cipher.ENCRYPT_MODE, privKey);
    String res = Hex.toHexString(engine.doFinal(data)).toUpperCase(Locale.ROOT);
    System.out.println(String.format("%s wrapped: %s", algo, res));
    return res;
  }

  private static String unwrap(String algo, Key privKey, byte[] data) throws Exception {
    Cipher engine = Cipher.getInstance(algo, prov);
    engine.init(Cipher.DECRYPT_MODE, privKey);
    String res = new String(engine.doFinal(data));
    System.out.println(String.format("%s unwrapped: %s", algo, res));
    return res;
  }
}

Is this an issue or have I just used the API wrong?

Kind Regards,
Michael Schäfer










SEEBURGER AG            Vorstand/SEEBURGER Executive Board:
Sitz der Gesellschaft/Registered Office:                Axel Haas, Michael Kleeberg, Friedemann Heinz, Dr. Martin Kuntz, Matthias Feßenbecker
Edisonstr. 1
D-75015 Bretten         Vorsitzende des Aufsichtsrats/Chairperson of the SEEBURGER Supervisory Board:
Tel.: 07252 / 96 - 0            Prof. Dr. Simone Zeuchner
Fax: 07252 / 96 - 2222
Internet: http://www.seeburger.de               Registergericht/Commercial Register:
e-mail: [hidden email]               HRB 240708 Mannheim


Dieses E-Mail ist nur für den Empfänger bestimmt, an den es gerichtet ist und kann vertrauliches bzw. unter das Berufsgeheimnis fallendes Material enthalten. Jegliche darin enthaltene Ansicht oder Meinungsäußerung ist die des Autors und stellt nicht notwendigerweise die Ansicht oder Meinung der SEEBURGER AG dar. Sind Sie nicht der Empfänger, so haben Sie diese E-Mail irrtümlich erhalten und jegliche Verwendung, Veröffentlichung, Weiterleitung, Abschrift oder jeglicher Druck dieser E-Mail ist strengstens untersagt. Weder die SEEBURGER AG noch der Absender (Eckenfels. Bernd) übernehmen die Haftung für Viren; es obliegt Ihrer Verantwortung, die E-Mail und deren Anhänge auf Viren zu prüfen.


This email is intended only for the recipient(s) to whom it is addressed. This email may contain confidential material that may be protected by professional secrecy. Any fact or opinion contained, or expression of the material herein, does not necessarily reflect that of SEEBURGER AG. If you are not the addressee or if you have received this email in error, any use, publication or distribution including forwarding, copying or printing is strictly prohibited. Neither SEEBURGER AG, nor the sender (Eckenfels. Bernd) accept liability for viruses; it is your responsibility to check this email and its attachments for viruses.