1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.conscrypt; 18 19 import java.io.IOException; 20 import java.io.NotSerializableException; 21 import java.io.ObjectInputStream; 22 import java.io.ObjectOutputStream; 23 import java.security.InvalidKeyException; 24 import java.util.Arrays; 25 26 import javax.crypto.SecretKey; 27 28 public class OpenSSLSecretKey implements SecretKey, OpenSSLKeyHolder { 29 private static final long serialVersionUID = 1831053062911514589L; 30 31 private final String algorithm; 32 private final int type; 33 private final byte[] encoded; 34 35 private transient OpenSSLKey key; 36 37 public OpenSSLSecretKey(String algorithm, byte[] encoded) { 38 this.algorithm = algorithm; 39 this.encoded = encoded; 40 41 type = NativeCrypto.EVP_PKEY_HMAC; 42 key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_mac_key(type, encoded)); 43 } 44 45 public OpenSSLSecretKey(String algorithm, OpenSSLKey key) { 46 this.algorithm = algorithm; 47 this.key = key; 48 49 type = NativeCrypto.EVP_PKEY_type(key.getPkeyContext()); 50 encoded = null; 51 } 52 53 public static OpenSSLKey getInstance(SecretKey key) throws InvalidKeyException { 54 try { 55 return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_mac_key(NativeCrypto.EVP_PKEY_HMAC, 56 key.getEncoded())); 57 } catch (Exception e) { 58 throw new InvalidKeyException(e); 59 } 60 } 61 62 @Override 63 public String getAlgorithm() { 64 return algorithm; 65 } 66 67 @Override 68 public String getFormat() { 69 if (key.isEngineBased()) { 70 return null; 71 } 72 73 return "RAW"; 74 } 75 76 @Override 77 public byte[] getEncoded() { 78 if (key.isEngineBased()) { 79 return null; 80 } 81 82 return encoded; 83 } 84 85 @Override 86 public OpenSSLKey getOpenSSLKey() { 87 return key; 88 } 89 90 @Override 91 public boolean equals(Object o) { 92 if (o == this) { 93 return true; 94 } 95 96 if (!(o instanceof SecretKey)) { 97 return false; 98 } 99 100 SecretKey other = (SecretKey) o; 101 if (!algorithm.equals(other.getAlgorithm())) { 102 return false; 103 } 104 105 if (o instanceof OpenSSLSecretKey) { 106 OpenSSLSecretKey otherOpenSSL = (OpenSSLSecretKey) o; 107 return key.equals(otherOpenSSL.getOpenSSLKey()); 108 } else if (key.isEngineBased()) { 109 return false; 110 } 111 112 if (!getFormat().equals(other.getFormat())) { 113 return false; 114 } 115 116 return Arrays.equals(encoded, other.getEncoded()); 117 } 118 119 @Override 120 public int hashCode() { 121 return key.hashCode(); 122 } 123 124 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 125 stream.defaultReadObject(); 126 127 key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_mac_key(type, encoded)); 128 } 129 130 private void writeObject(ObjectOutputStream stream) throws IOException { 131 if (getOpenSSLKey().isEngineBased()) { 132 throw new NotSerializableException("engine-based keys can not be serialized"); 133 } 134 135 stream.defaultWriteObject(); 136 } 137 } 138