blob: 6413aded387f22307aba3a00b4e01539c3cd0f64 [file] [log] [blame]
/*
* Copyright (C) 2019 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 com.android.internal.net.eap.crypto;
import com.android.internal.annotations.VisibleForTesting;
/**
* This class sets parity-bits for a given byte-array as specified by the MSCHAPv2 standard.
*
* @see <a href="https://tools.ietf.org/html/rfc2759">RFC 2759, Microsoft PPP CHAP Extensions,
* Version 2 (MSCHAPv2)</a>
*/
public class ParityBitUtil {
private static final int INPUT_LENGTH = 7;
private static final int OUTPUT_LENGTH = 8;
private static final int BITS_PER_BYTE = 8;
private static final int BITS_PER_PARITY_BIT = 7;
private static final byte MASK = (byte) 0xFE;
/**
* Computes and returns a byte[] with the odd-parity bits set.
*
* <p>Parity bits are set for the 8th, 16th, 24th, etc. bits as the LSB for each byte.
*
* @param input byte[] the input data requiring parity bits
* @return byte[] the input byte[] with its parity-bits set
* @throws IllegalArgumentException iff the given data array does not contain 7 bytes
*/
public static byte[] addParityBits(byte[] input) {
if (input.length != INPUT_LENGTH) {
throw new IllegalArgumentException("Data must be 7B long");
}
byte[] output = new byte[OUTPUT_LENGTH];
long allBits = byteArrayToLong(input) << 1; // make room for parity bit
// allBits stores input bits as [b56, ..., b1, 0]. Consuming allBits in reverse populates
// output with a right shift
for (int i = output.length - 1; i >= 0; i--) {
output[i] = getByteWithParityBit((byte) allBits);
allBits >>= BITS_PER_PARITY_BIT;
}
return output;
}
@VisibleForTesting
static byte getByteWithParityBit(byte b) {
// Parity bits per RFC 2759#8.6
byte parity =
(byte) ((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 4) ^ (b >> 3) ^ (b >> 2) ^ (b >> 1));
// If we have an odd number of bits, b1 should be 0.
// If we have an even number of bits, b1 should be 1.
byte parityBit = (byte) (~parity & 1);
return (byte) ((b & MASK) | parityBit);
}
@VisibleForTesting
static long byteArrayToLong(byte[] input) {
long result = 0;
for (int i = 0; i < input.length; i++) {
result = (result << BITS_PER_BYTE) | Byte.toUnsignedInt(input[i]);
}
return result;
}
}