content: /**
   * Copyright (c) 2016, The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.net.wifi;
  
  import android.os.Parcel;
  
  import java.io.ByteArrayInputStream;
  import java.security.KeyFactory;
  import java.security.NoSuchAlgorithmException;
  import java.security.PrivateKey;
  import java.security.cert.CertificateEncodingException;
  import java.security.cert.CertificateException;
  import java.security.cert.CertificateFactory;
  import java.security.cert.X509Certificate;
  import java.security.spec.InvalidKeySpecException;
  import java.security.spec.PKCS8EncodedKeySpec;
  
  /**
   * Provides utilities for writing/reading a non-Parcelable objects to/from
   * a Parcel object.
   *
   * @hide
   */
  public class ParcelUtil {
      /**
       * Write a PrivateKey object |key| to the specified Parcel |dest|.
       *
       * Below is the data format:
       * |algorithm|     -> String of algorithm name
       * |endcodedKey|  -> byte[] of key data
       *
       * For a null PrivateKey object, a null string will be written to |algorithm| and
       * |encodedKey| will be skipped. Since a PrivateKey can only be constructed with
       * a valid algorithm String.
       *
       * @param dest Parcel object to write to
       * @param key PrivateKey object to read from.
       */
      public static void writePrivateKey(Parcel dest, PrivateKey key) {
          if (key == null) {
              dest.writeString(null);
              return;
          }
  
          dest.writeString(key.getAlgorithm());
          dest.writeByteArray(key.getEncoded());
      }
  
      /**
       * Read/create a PrivateKey object from a specified Parcel object |in|.
       *
       * Refer to the function above for the expected data format.
       *
       * @param in Parcel object to read from
       * @return a PrivateKey object or null
       */
      public static PrivateKey readPrivateKey(Parcel in) {
          String algorithm = in.readString();
          if (algorithm == null) {
              return null;
          }
  
          byte[] userKeyBytes = in.createByteArray();
          try {
              KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
              return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(userKeyBytes));
         } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
              return null;
         }
      }
  
      /**
       * Write a X509Certificate object |cert| to a Parcel object |dest|.
       * The data being written to the Parcel is just a byte[] of the encoded certificate data.
       *
       * @param dest Parcel object to write to
       * @param cert X509Certificate object to read from
       */
      public static void writeCertificate(Parcel dest, X509Certificate cert) {
          byte[] certBytes = null;
          if (cert != null) {
              try {
                  certBytes = cert.getEncoded();
              } catch (CertificateEncodingException e) {
                  /* empty, write null. */
              }
          }
          dest.writeByteArray(certBytes);
      }
  
      /**
       * Read/create a X509Certificate object from a specified Parcel object |in|.
       *
       * @param in Parcel object to read from
       * @return a X509Certficate object or null
       */
      public static X509Certificate readCertificate(Parcel in) {
          byte[] certBytes = in.createByteArray();
          if (certBytes == null) {
              return null;
          }
  
          try {
              CertificateFactory cFactory = CertificateFactory.getInstance("X.509");
              return (X509Certificate) cFactory
                      .generateCertificate(new ByteArrayInputStream(certBytes));
          } catch (CertificateException e) {
              return null;
          }
      }
  
      /**
       * Write an array of X509Certificate objects |certs| to a Parcel object |dest|.
       * The data being written to the Parcel are consist of an integer indicating
       * the size of the array and the certificates data.  Certificates data will be
       * skipped for a null array or size of 0 array.
       *
       * @param dest Parcel object to write to
       * @param certs array of X509Certificate objects to read from
       */
      public static void writeCertificates(Parcel dest, X509Certificate[] certs) {
          if (certs == null || certs.length == 0) {
              dest.writeInt(0);
              return;
          }
  
          dest.writeInt(certs.length);
          for (int i = 0; i < certs.length; i++) {
              writeCertificate(dest, certs[i]);
          }
      }
  
      /**
       * Read/create an array of X509Certificate objects from a specified Parcel object |in|.
       *
       * @param in Parcel object to read from
       * @return X509Certficate[] or null
       */
      public static X509Certificate[] readCertificates(Parcel in) {
          int length = in.readInt();
          if (length == 0) {
              return null;
          }
  
          X509Certificate[] certs = new X509Certificate[length];
          for (int i = 0; i < length; i++) {
              certs[i] = readCertificate(in);
          }
          return certs;
      }
  }
  