1720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root/*
2720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root * Copyright (C) 2012 The Android Open Source Project
3720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root *
4720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root * Licensed under the Apache License, Version 2.0 (the "License");
5720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root * you may not use this file except in compliance with the License.
6720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root * You may obtain a copy of the License at
7720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root *
8720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root *      http://www.apache.org/licenses/LICENSE-2.0
9720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root *
10720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root * Unless required by applicable law or agreed to in writing, software
11720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root * distributed under the License is distributed on an "AS IS" BASIS,
12720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root * See the License for the specific language governing permissions and
14720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root * limitations under the License.
15720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root */
16720b2bf27d36d92aa7f39ab627968aa7346e7904Kenny Root
17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt;
18e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
19e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubinimport java.nio.ByteBuffer;
20e4b82368b271aa959783814dde0087c84aed53b5Kenny Rootimport java.security.InvalidAlgorithmParameterException;
21e4b82368b271aa959783814dde0087c84aed53b5Kenny Rootimport java.security.InvalidKeyException;
22e4b82368b271aa959783814dde0087c84aed53b5Kenny Rootimport java.security.Key;
23e4b82368b271aa959783814dde0087c84aed53b5Kenny Rootimport java.security.NoSuchAlgorithmException;
24e4b82368b271aa959783814dde0087c84aed53b5Kenny Rootimport java.security.spec.AlgorithmParameterSpec;
25e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
26e4b82368b271aa959783814dde0087c84aed53b5Kenny Rootimport javax.crypto.MacSpi;
27e4b82368b271aa959783814dde0087c84aed53b5Kenny Rootimport javax.crypto.SecretKey;
28e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
29e4b82368b271aa959783814dde0087c84aed53b5Kenny Rootpublic abstract class OpenSSLMac extends MacSpi {
30a00142199f81acd00671d07d288845b5a5f15381David Benjamin    private NativeRef.HMAC_CTX ctx;
31e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
32e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    /**
33e4b82368b271aa959783814dde0087c84aed53b5Kenny Root     * Holds the EVP_MD for the hashing algorithm, e.g.
34e4b82368b271aa959783814dde0087c84aed53b5Kenny Root     * EVP_get_digestbyname("sha1");
35e4b82368b271aa959783814dde0087c84aed53b5Kenny Root     */
3638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice    private final long evp_md;
37e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
38e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    /**
39e4b82368b271aa959783814dde0087c84aed53b5Kenny Root     * The secret key used in this keyed MAC.
40e4b82368b271aa959783814dde0087c84aed53b5Kenny Root     */
41a00142199f81acd00671d07d288845b5a5f15381David Benjamin    private byte[] keyBytes;
42e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
43e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    /**
44e4b82368b271aa959783814dde0087c84aed53b5Kenny Root     * Holds the output size of the message digest.
45e4b82368b271aa959783814dde0087c84aed53b5Kenny Root     */
46e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    private final int size;
47e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
48e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    /**
49e4b82368b271aa959783814dde0087c84aed53b5Kenny Root     * Holds a dummy buffer for writing single bytes to the digest.
50e4b82368b271aa959783814dde0087c84aed53b5Kenny Root     */
51e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    private final byte[] singleByte = new byte[1];
52e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
53a00142199f81acd00671d07d288845b5a5f15381David Benjamin    private OpenSSLMac(long evp_md, int size) {
54e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        this.evp_md = evp_md;
55e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        this.size = size;
56e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
57e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
58e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    @Override
59e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    protected int engineGetMacLength() {
60e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        return size;
61e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
62e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
63e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    @Override
64e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
65e4b82368b271aa959783814dde0087c84aed53b5Kenny Root            InvalidAlgorithmParameterException {
66e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        if (!(key instanceof SecretKey)) {
67e4b82368b271aa959783814dde0087c84aed53b5Kenny Root            throw new InvalidKeyException("key must be a SecretKey");
68e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        }
69e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
70e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        if (params != null) {
71e4b82368b271aa959783814dde0087c84aed53b5Kenny Root            throw new InvalidAlgorithmParameterException("unknown parameter type");
72e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        }
73e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
74a00142199f81acd00671d07d288845b5a5f15381David Benjamin        keyBytes = key.getEncoded();
75a00142199f81acd00671d07d288845b5a5f15381David Benjamin        if (keyBytes == null) {
76a00142199f81acd00671d07d288845b5a5f15381David Benjamin            throw new InvalidKeyException("key cannot be encoded");
77e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        }
78e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
79652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        resetContext();
80e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
81e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
82652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root    private final void resetContext() {
83a00142199f81acd00671d07d288845b5a5f15381David Benjamin        NativeRef.HMAC_CTX ctxLocal = new NativeRef.HMAC_CTX(NativeCrypto.HMAC_CTX_new());
84a00142199f81acd00671d07d288845b5a5f15381David Benjamin        if (keyBytes != null) {
85a00142199f81acd00671d07d288845b5a5f15381David Benjamin            NativeCrypto.HMAC_Init_ex(ctxLocal, keyBytes, evp_md);
86c41697ab2043f5b0e0f86b6731519eb72e3569e5Kenny Root        }
87652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root
88652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        this.ctx = ctxLocal;
89e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
90e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
91e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    @Override
92e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    protected void engineUpdate(byte input) {
93e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        singleByte[0] = input;
94e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        engineUpdate(singleByte, 0, 1);
95e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
96e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
97e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    @Override
98e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    protected void engineUpdate(byte[] input, int offset, int len) {
99a00142199f81acd00671d07d288845b5a5f15381David Benjamin        final NativeRef.HMAC_CTX ctxLocal = ctx;
100a00142199f81acd00671d07d288845b5a5f15381David Benjamin        NativeCrypto.HMAC_Update(ctxLocal, input, offset, len);
101e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
102e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
103e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    @Override
104e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin    protected void engineUpdate(ByteBuffer input) {
105e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        // Optimization: Avoid copying/allocation for direct buffers because their contents are
106e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        // stored as a contiguous region in memory and thus can be efficiently accessed from native
107e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        // code.
108e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin
109e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        if (!input.hasRemaining()) {
110e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin            return;
111e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        }
112e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin
113e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        if (!input.isDirect()) {
114e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin            super.engineUpdate(input);
115e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin            return;
116e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        }
117e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin
118e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        long baseAddress = NativeCrypto.getDirectBufferAddress(input);
119e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        if (baseAddress == 0) {
120e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin            // Direct buffer's contents can't be accessed from JNI  -- superclass's implementation
121e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin            // is good enough to handle this.
122e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin            super.engineUpdate(input);
123e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin            return;
124e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        }
125e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin
126e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        // MAC the contents between Buffer's position and limit (remaining() number of bytes)
127e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        int position = input.position();
12849ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin        if (position < 0) {
12949ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin            throw new RuntimeException("Negative position");
130e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        }
13149ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin        long ptr = baseAddress + position;
132e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        int len = input.remaining();
13349ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin        if (len < 0) {
13449ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin            throw new RuntimeException("Negative remaining amount");
135e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        }
136e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin
137e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        final NativeRef.HMAC_CTX ctxLocal = ctx;
138e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        NativeCrypto.HMAC_UpdateDirect(ctxLocal, ptr, len);
139e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin        input.position(position + len);
140e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin    }
141e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin
142e33d066caa6fff22e17e807abcdff9bc4f746bb0Alex Klyubin    @Override
143e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    protected byte[] engineDoFinal() {
144a00142199f81acd00671d07d288845b5a5f15381David Benjamin        final NativeRef.HMAC_CTX ctxLocal = ctx;
145a00142199f81acd00671d07d288845b5a5f15381David Benjamin        final byte[] output = NativeCrypto.HMAC_Final(ctxLocal);
146652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        resetContext();
147e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        return output;
148e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
149e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
150e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    @Override
151e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    protected void engineReset() {
152652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        resetContext();
153e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
154e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
155e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    public static class HmacMD5 extends OpenSSLMac {
15638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("md5");
157e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
158e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
159e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        public HmacMD5() {
160a00142199f81acd00671d07d288845b5a5f15381David Benjamin            super(EVP_MD, SIZE);
161e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        }
162e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
163e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
164e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    public static class HmacSHA1 extends OpenSSLMac {
16538c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1");
166e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
167e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
168e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        public HmacSHA1() {
169a00142199f81acd00671d07d288845b5a5f15381David Benjamin            super(EVP_MD, SIZE);
170e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        }
171e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
172e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
173d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root    public static class HmacSHA224 extends OpenSSLMac {
174d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha224");
175d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
176d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root
177d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        public HmacSHA224() throws NoSuchAlgorithmException {
178a00142199f81acd00671d07d288845b5a5f15381David Benjamin            super(EVP_MD, SIZE);
179d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        }
180d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root    }
181d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root
182e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    public static class HmacSHA256 extends OpenSSLMac {
18338c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256");
184e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
185e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
186e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        public HmacSHA256() throws NoSuchAlgorithmException {
187a00142199f81acd00671d07d288845b5a5f15381David Benjamin            super(EVP_MD, SIZE);
188e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        }
189e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
190e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
191e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    public static class HmacSHA384 extends OpenSSLMac {
19238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384");
193e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
194e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
195e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        public HmacSHA384() throws NoSuchAlgorithmException {
196a00142199f81acd00671d07d288845b5a5f15381David Benjamin            super(EVP_MD, SIZE);
197e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        }
198e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
199e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
200e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    public static class HmacSHA512 extends OpenSSLMac {
20138c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512");
202e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
203e4b82368b271aa959783814dde0087c84aed53b5Kenny Root
204e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        public HmacSHA512() {
205a00142199f81acd00671d07d288845b5a5f15381David Benjamin            super(EVP_MD, SIZE);
206e4b82368b271aa959783814dde0087c84aed53b5Kenny Root        }
207e4b82368b271aa959783814dde0087c84aed53b5Kenny Root    }
208e4b82368b271aa959783814dde0087c84aed53b5Kenny Root}
209