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