1 /* 2 * Copyright 2015 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.security.AlgorithmParametersSpi; 21 import java.security.spec.AlgorithmParameterSpec; 22 import java.security.spec.InvalidParameterSpecException; 23 24 /** 25 * GCM parameters used during an ciphering operation with {@link OpenSSLCipher}. 26 * This class is used internally for backward compatibility with Android versions 27 * that did not have the {@code GCMParameterSpec} class, in addition to being the 28 * implementation of the GCM AlgorithmParameters implementation. 29 * <p> 30 * The only supported encoding format is ASN.1, as specified in RFC 5084 section 3.2. 31 * 32 * @hide 33 */ 34 @Internal 35 public final class GCMParameters extends AlgorithmParametersSpi { 36 37 // The default value (in bits) for TLEN in the GCM ASN.1 module 38 private static final int DEFAULT_TLEN = 96; 39 40 /** The tag length in bits. */ 41 private int tLen; 42 43 /** Actually the nonce value for the GCM operation. */ 44 private byte[] iv; 45 46 public GCMParameters() { } 47 48 GCMParameters(int tLen, byte[] iv) { 49 this.tLen = tLen; 50 this.iv = iv; 51 } 52 53 /** 54 * Returns the tag length in bits. 55 */ 56 int getTLen() { 57 return tLen; 58 } 59 60 /** 61 * Returns a non-cloned version of the IV. 62 */ 63 byte[] getIV() { 64 return iv; 65 } 66 67 @Override 68 protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec) 69 throws InvalidParameterSpecException { 70 GCMParameters params = Platform.fromGCMParameterSpec(algorithmParameterSpec); 71 if (params == null) { 72 throw new InvalidParameterSpecException("Only GCMParameterSpec is supported"); 73 } 74 this.tLen = params.tLen; 75 this.iv = params.iv; 76 } 77 78 @Override 79 protected void engineInit(byte[] bytes) throws IOException { 80 long readRef = 0; 81 long seqRef = 0; 82 try { 83 readRef = NativeCrypto.asn1_read_init(bytes); 84 seqRef = NativeCrypto.asn1_read_sequence(readRef); 85 byte[] newIv = NativeCrypto.asn1_read_octetstring(seqRef); 86 int newTlen = DEFAULT_TLEN; 87 if (!NativeCrypto.asn1_read_is_empty(seqRef)) { 88 newTlen = 8 * (int) NativeCrypto.asn1_read_uint64(seqRef); 89 } 90 if (!NativeCrypto.asn1_read_is_empty(seqRef) 91 || !NativeCrypto.asn1_read_is_empty(readRef)) { 92 throw new IOException("Error reading ASN.1 encoding"); 93 } 94 this.iv = newIv; 95 this.tLen = newTlen; 96 } finally { 97 NativeCrypto.asn1_read_free(seqRef); 98 NativeCrypto.asn1_read_free(readRef); 99 } 100 } 101 102 @Override 103 protected void engineInit(byte[] bytes, String format) throws IOException { 104 if ((format == null) || format.equals("ASN.1")) { 105 engineInit(bytes); 106 } else { 107 throw new IOException("Unsupported format: " + format); 108 } 109 } 110 111 @Override 112 protected <T extends AlgorithmParameterSpec> T engineGetParameterSpec(Class<T> aClass) 113 throws InvalidParameterSpecException { 114 if ((aClass != null) && aClass.getName().equals("javax.crypto.spec.GCMParameterSpec")) { 115 return aClass.cast(Platform.toGCMParameterSpec(tLen, iv)); 116 } else { 117 throw new InvalidParameterSpecException("Unsupported class: " + aClass); 118 } 119 } 120 121 @Override 122 protected byte[] engineGetEncoded() throws IOException { 123 long cbbRef = 0; 124 long seqRef = 0; 125 try { 126 cbbRef = NativeCrypto.asn1_write_init(); 127 seqRef = NativeCrypto.asn1_write_sequence(cbbRef); 128 NativeCrypto.asn1_write_octetstring(seqRef, this.iv); 129 if (this.tLen != DEFAULT_TLEN) { 130 NativeCrypto.asn1_write_uint64(seqRef, this.tLen / 8); 131 } 132 return NativeCrypto.asn1_write_finish(cbbRef); 133 } catch (IOException e) { 134 NativeCrypto.asn1_write_cleanup(cbbRef); 135 throw e; 136 } finally { 137 NativeCrypto.asn1_write_free(seqRef); 138 NativeCrypto.asn1_write_free(cbbRef); 139 } 140 } 141 142 @Override 143 protected byte[] engineGetEncoded(String format) throws IOException { 144 if ((format == null) || format.equals("ASN.1")) { 145 return engineGetEncoded(); 146 } 147 throw new IOException("Unsupported format: " + format); 148 } 149 150 @Override 151 protected String engineToString() { 152 return "Conscrypt GCM AlgorithmParameters"; 153 } 154 } 155