зеркало из https://github.com/mozilla/pluotsorbet.git
Merge pull request #458 from PinZhang/pzhang/security-classes
Pzhang/security classes
This commit is contained in:
Коммит
7c7e300323
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.midp.crypto;
|
||||
|
||||
/**
|
||||
* Wrapper for all AES cipher classes.
|
||||
*/
|
||||
public class AES extends Cipher {
|
||||
Cipher cipher;
|
||||
|
||||
/**
|
||||
* Public by name constructor.
|
||||
*/
|
||||
public AES() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the factory method to set the mode and padding parameters.
|
||||
* Need because Class.newInstance does not take args.
|
||||
*
|
||||
* @param mode the mode parsed from the transformation parameter of
|
||||
* getInstance
|
||||
* @param padding the paddinge parsed from the transformation parameter of
|
||||
* getInstance
|
||||
*
|
||||
* @exception NoSuchPaddingException if <code>transformation</code>
|
||||
* contains a padding scheme that is not available.
|
||||
*/
|
||||
protected void setChainingModeAndPadding(String mode, String padding)
|
||||
throws NoSuchPaddingException {
|
||||
if (mode.equals("ECB") || mode.equals("")) {
|
||||
cipher = new AES_ECB();
|
||||
} else if (mode.equals("CBC")) {
|
||||
cipher = new AES_CBC();
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
cipher.setChainingModeAndPadding(mode, padding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this cipher with a key and a set of algorithm
|
||||
* parameters.
|
||||
*/
|
||||
public void init(int opmode, Key key, CryptoParameter params)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
cipher.init(opmode, key, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continues a multiple-part encryption or decryption operation
|
||||
* (depending on how this cipher was initialized), processing another data
|
||||
* part.
|
||||
*/
|
||||
public int update(byte[] input, int inputOffset, int inputLen,
|
||||
byte[] output, int outputOffset)
|
||||
throws IllegalStateException, ShortBufferException {
|
||||
return cipher.update(input, inputOffset, inputLen, output,
|
||||
outputOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts or decrypts data in a single-part operation, or finishes a
|
||||
* multiple-part operation. The data is encrypted or decrypted,
|
||||
* depending on how this cipher was initialized.
|
||||
*/
|
||||
public int doFinal(byte[] input, int inputOffset, int inputLen,
|
||||
byte[] output, int outputOffset)
|
||||
throws IllegalStateException, ShortBufferException,
|
||||
IllegalBlockSizeException, BadPaddingException {
|
||||
return cipher.doFinal(input, inputOffset, inputLen, output,
|
||||
outputOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the initialization vector (IV) in a new buffer.
|
||||
* This is useful in the case where a random IV was created.
|
||||
* @return the initialization vector in a new buffer,
|
||||
* or <code>null</code> if the underlying algorithm does
|
||||
* not use an IV, or if the IV has not yet been set.
|
||||
*/
|
||||
public byte[] getIV() {
|
||||
return cipher.getIV();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.midp.crypto;
|
||||
|
||||
/**
|
||||
* AES CBC Cipher.
|
||||
*/
|
||||
public class AES_CBC extends AES_ECB {
|
||||
|
||||
/** Internal buffer. */
|
||||
private byte[] scratchPad;
|
||||
|
||||
/** Saved internal buffer. */
|
||||
private byte[] savedState;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public AES_CBC() {
|
||||
super();
|
||||
scratchPad = new byte[BLOCK_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this cipher with a key and a set of algorithm
|
||||
* parameters.
|
||||
* @param mode the operation mode of this cipher
|
||||
* @param key the encryption key
|
||||
* @param params the algorithm parameters
|
||||
* @exception java.security.InvalidKeyException if the given key
|
||||
* is inappropriate for initializing this cipher
|
||||
* @exception java.security.InvalidAlgorithmParameterException
|
||||
* if the given algorithm parameters are inappropriate for this cipher
|
||||
*/
|
||||
public void init(int mode, Key key, CryptoParameter params)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
doInit(mode, "AES", key, true, params);
|
||||
System.arraycopy(IV, 0, state, 0, BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts or decrypts data in a single-part operation, or finishes a
|
||||
* multiple-part operation. The data is encrypted or decrypted,
|
||||
* depending on how this cipher was initialized.
|
||||
*
|
||||
* @param inBuff the input buffer
|
||||
* @param inOffset the offset in <code>input</code> where the input
|
||||
* starts
|
||||
* @param inLength the input length
|
||||
* @param outBuff the buffer for the result
|
||||
* @param outOffset the offset in <code>output</code> where the result
|
||||
* is stored
|
||||
*
|
||||
* @return the number of bytes stored in <code>output</code>
|
||||
*
|
||||
* @exception IllegalStateException if this cipher is in a wrong state
|
||||
* (e.g., has not been initialized)
|
||||
* @exception javax.crypto.IllegalBlockSizeException if this cipher is a
|
||||
* block cipher,
|
||||
* no padding has been requested (only in encryption mode), and the total
|
||||
* input length of the data processed by this cipher is not a multiple of
|
||||
* block size
|
||||
* @exception javax.crypto.ShortBufferException if the given output buffer
|
||||
* is too small to hold the result
|
||||
* @exception javax.crypto.BadPaddingException if this cipher is in
|
||||
* decryption mode,
|
||||
* and (un)padding has been requested, but the decrypted data is not
|
||||
* bounded by the appropriate padding bytes
|
||||
*/
|
||||
public int doFinal(byte inBuff[], int inOffset, int inLength,
|
||||
byte outBuff[], int outOffset)
|
||||
throws IllegalStateException, IllegalBlockSizeException,
|
||||
ShortBufferException, BadPaddingException {
|
||||
int result = super.doFinal(inBuff, inOffset, inLength,
|
||||
outBuff, outOffset);
|
||||
System.arraycopy(IV, 0, state, 0, BLOCK_SIZE);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Depending on the mode, either encrypts or decrypts one block.
|
||||
* @param out will contain the result of encryption
|
||||
* or decryption operation
|
||||
* @param offset is the offset in out
|
||||
*/
|
||||
protected void processBlock(byte[] out, int offset) {
|
||||
|
||||
if (mode == Cipher.ENCRYPT_MODE) {
|
||||
Util.xorArrays(holdData, state);
|
||||
cipherBlock();
|
||||
System.arraycopy(state, 0, out, offset, BLOCK_SIZE);
|
||||
} else {
|
||||
System.arraycopy(state, 0, scratchPad, 0, BLOCK_SIZE);
|
||||
decipherBlock();
|
||||
Util.xorArrays(state, scratchPad);
|
||||
System.arraycopy(state, 0, out, offset, BLOCK_SIZE);
|
||||
System.arraycopy(holdData, 0, state, 0, BLOCK_SIZE);
|
||||
}
|
||||
holdCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves internal state.
|
||||
*/
|
||||
protected void saveState() {
|
||||
super.saveState();
|
||||
savedState = Util.cloneArray(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores internal state.
|
||||
*/
|
||||
protected void restoreState() {
|
||||
super.restoreState();
|
||||
state = savedState;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Portions Copyright 2000-2009 Sun Microsystems, Inc. All Rights
|
||||
* Reserved. Use is subject to license terms.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*
|
||||
* Copyright (c) 1995-2005 The Cryptix Foundation Limited.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND
|
||||
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.sun.midp.crypto;
|
||||
|
||||
/**
|
||||
* This class is an implementation of AES cipher in ECB mode.
|
||||
*/
|
||||
public class AES_ECB extends BlockCipherBase {
|
||||
|
||||
/** Substitution values. */
|
||||
private static final byte[] SBox = Util.unpackBytes(
|
||||
"c|w{rkoE0\001g+~W+vJ\002I}zYGp-T\042/\034$r@7}\023&6?wL4%" +
|
||||
"eqqX1\025\004G#C\030\026\005\032\007\022\000bk'2u\011\003" +
|
||||
",\032\033nZ\040R;V3)c/\004SQ\000m\040|1[jK>9JLXOPo*{CM3" +
|
||||
"\005Ey\002P<\037(Q#@\017\022\0358u<6Z!\020sRM\014\023l_" +
|
||||
"\027D\027D'~=d]\031s`\001O\134\042*\020\010Fn8\024^^\013[" +
|
||||
"`2:\012I\006$\134BS,b\021\025dygH7m\015UN)lVtjez.\010:x%." +
|
||||
"\034&4Fh]t\037K=\013\012p>5fH\003v\016a5W9\006A\035\036ax" +
|
||||
"\030\021iY\016\024\033\036\007iNU(_\014!\011\015?fBhA\031" +
|
||||
"-\0170T;\026\020a]|{X\013U\134\0042Ufp#a:O'\031\040Ye\000" +
|
||||
"wf2\012>\034\021\134g;^\021\005");
|
||||
|
||||
/** Inverse substitution table. */
|
||||
private static final byte[] ISBox;
|
||||
|
||||
static {
|
||||
ISBox = new byte[256];
|
||||
for (int i = 0; i < 256; i++) {
|
||||
ISBox[SBox[i] & 0xff] = (byte) i;
|
||||
}
|
||||
}
|
||||
|
||||
/** Precalculated table for matrix multiplication. */
|
||||
private int[] SB0;
|
||||
/** Precalculated table for matrix multiplication. */
|
||||
private int[] SB1;
|
||||
/** Precalculated table for matrix multiplication. */
|
||||
private int[] SB2;
|
||||
/** Precalculated table for matrix multiplication. */
|
||||
private int[] SB3;
|
||||
|
||||
/**
|
||||
* Round constants.
|
||||
*/
|
||||
private static final byte[] Rcon = Util.unpackBytes(
|
||||
"\000\001\002\004\010\020\040@\000\0336l\000\002");
|
||||
|
||||
/** AES ciphers encrypt/decrypt in block size of 16 bytes. */
|
||||
static final int BLOCK_SIZE = 16;
|
||||
|
||||
/** Number of columns (32-bit words) comprising the state. */
|
||||
private static final int Nb = 4;
|
||||
|
||||
/**
|
||||
* Number of 32-bit words comprising the key (4, 6, 8 for 128, 192
|
||||
* and 256 bits).
|
||||
*/
|
||||
private int Nk;
|
||||
|
||||
/** Number of rounds (10, 12, 14). */
|
||||
private int Nr;
|
||||
|
||||
/**
|
||||
* Key Schedule. Length depends on Block and Key length.
|
||||
* Block length = 128 bits or 16 bytes. For 128 bit key
|
||||
* W.length = Nb * (Nr + 1) == 4(10 + 1) = 44 Words = 44 * 4 bytes =
|
||||
* 176 bytes
|
||||
*/
|
||||
private int[] W;
|
||||
|
||||
/** Internal buffer. */
|
||||
protected byte[] state;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public AES_ECB() {
|
||||
super(BLOCK_SIZE);
|
||||
state = new byte[BLOCK_SIZE];
|
||||
SB0 = new int[256];
|
||||
SB1 = new int[256];
|
||||
SB2 = new int[256];
|
||||
SB3 = new int[256];
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the factory method to set the mode and padding parameters.
|
||||
* Need because Class.newInstance does not take args.
|
||||
*
|
||||
* @param mode the mode parsed from the transformation parameter of
|
||||
* getInstance and upper cased
|
||||
* @param padding the paddinge parsed from the transformation parameter of
|
||||
* getInstance and upper cased
|
||||
*/
|
||||
protected void setChainingModeAndPadding(String mode, String padding)
|
||||
throws NoSuchPaddingException {
|
||||
// Note: The chaining mode is implicitly set by using this class.
|
||||
|
||||
setPadding(padding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this cipher with a key and a set of algorithm
|
||||
* parameters.
|
||||
* @param mode the operation mode of this cipher
|
||||
* @param key the encryption key
|
||||
* @param params the algorithm parameters
|
||||
* @exception java.security.InvalidKeyException if the given key
|
||||
* is inappropriate for initializing this cipher
|
||||
* @exception java.security.InvalidAlgorithmParameterException
|
||||
* if the given algorithm parameters are inappropriate for this cipher
|
||||
*/
|
||||
public void init(int mode, Key key, CryptoParameter params)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
|
||||
doInit(mode, "AES", key, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes key.
|
||||
* @param data key data
|
||||
* @param mode cipher mode
|
||||
* @exception InvalidKeyException if the given key is inappropriate
|
||||
* for this cipher
|
||||
*/
|
||||
void initKey(byte[] data, int mode) throws InvalidKeyException {
|
||||
|
||||
// Min key 128 bits, max key 256 bits
|
||||
if (data.length != 16 && data.length != 24 && data.length != 32) {
|
||||
throw new InvalidKeyException();
|
||||
}
|
||||
|
||||
Nk = data.length >> 2;
|
||||
Nr = 6 + Nk;
|
||||
|
||||
int row = 0x0e090d0b;
|
||||
byte[] box = ISBox;
|
||||
if (mode == Cipher.ENCRYPT_MODE) {
|
||||
row = 0x02010103;
|
||||
box = SBox;
|
||||
}
|
||||
|
||||
if (multiply(row, box[0]) != SB0[0]) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
int j;
|
||||
SB0[i] = j = multiply(row, box[i]);
|
||||
SB1[i] = (j >>> 8) | (j << 24);
|
||||
SB2[i] = (j >>> 16) | (j << 16);
|
||||
SB3[i] = (j >>> 24) | (j << 8);
|
||||
}
|
||||
}
|
||||
|
||||
KeyExpansion(data, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates values for matrix multiplication.
|
||||
* @param a represents a matrix column (4 bytes).
|
||||
* @param b multiplier
|
||||
* @return result of multiplication.
|
||||
*/
|
||||
private static int multiply(int a, int b) {
|
||||
int result = 0;
|
||||
b &= 0xff;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result ^= ((a >> i) & 0x01010101) * b;
|
||||
b = b < 128 ? b << 1 : (b << 1) ^ 0x11b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on the mode, either encrypts or decrypts data block.
|
||||
* @param out will contain the result of encryption
|
||||
* or decryption operation
|
||||
* @param offset is the offset in out
|
||||
*/
|
||||
protected void processBlock(byte[] out, int offset) {
|
||||
|
||||
holdCount = 0;
|
||||
|
||||
if (mode == Cipher.ENCRYPT_MODE) {
|
||||
cipherBlock();
|
||||
} else {
|
||||
decipherBlock();
|
||||
}
|
||||
|
||||
System.arraycopy(state, 0, out, offset, BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the encryption of data.
|
||||
*/
|
||||
protected void cipherBlock() {
|
||||
|
||||
int t0 = Util.getInt(holdData, 0) ^ W[0];
|
||||
int t1 = Util.getInt(holdData, 4) ^ W[1];
|
||||
int t2 = Util.getInt(holdData, 8) ^ W[2];
|
||||
int t3 = Util.getInt(holdData, 12) ^ W[3];
|
||||
|
||||
int j = 4;
|
||||
for (int i = 1; i < Nr; i++) {
|
||||
int v0, v1, v2;
|
||||
t0 = SB0[(v0 = t0) >>> 24] ^ SB1[(v1 = t1) >>> 16 & 0xff] ^
|
||||
SB2[(v2 = t2) >>> 8 & 0xff] ^ SB3[t3 & 0xff] ^ W[j];
|
||||
t1 = SB0[v1 >>> 24] ^ SB1[v2 >>> 16 & 0xff] ^
|
||||
SB2[t3 >>> 8 & 0xff] ^ SB3[v0 & 0xff] ^ W[j + 1];
|
||||
t2 = SB0[v2 >>> 24] ^ SB1[t3 >>> 16 & 0xff] ^
|
||||
SB2[v0 >>> 8 & 0xff] ^ SB3[v1 & 0xff] ^ W[j + 2];
|
||||
t3 = SB0[t3 >>> 24] ^ SB1[v0 >>> 16 & 0xff] ^
|
||||
SB2[v1 >>> 8 & 0xff] ^ SB3[v2 & 0xff] ^ W[j + 3];
|
||||
j += 4;
|
||||
}
|
||||
|
||||
int k;
|
||||
byte out[];
|
||||
(out = state)[0] = (byte)(SBox[t0 >>> 24] ^ (k = W[j]) >>> 24);
|
||||
out[1] = (byte)(SBox[t1 >>> 16 & 0xff] ^ k >>> 16);
|
||||
out[2] = (byte)(SBox[t2 >>> 8 & 0xff] ^ k >>> 8);
|
||||
out[3] = (byte)(SBox[t3 & 0xff] ^ k);
|
||||
out[4] = (byte)(SBox[t1 >>> 24] ^ (k = W[j + 1]) >>> 24);
|
||||
out[5] = (byte)(SBox[t2 >>> 16 & 0xff] ^ k >>> 16);
|
||||
out[6] = (byte)(SBox[t3 >>> 8 & 0xff] ^ k >>> 8);
|
||||
out[7] = (byte)(SBox[t0 & 0xff] ^ k);
|
||||
out[8] = (byte)(SBox[t2 >>> 24] ^ (k = W[j + 2]) >>> 24);
|
||||
out[9] = (byte)(SBox[t3 >>> 16 & 0xff] ^ k >>> 16);
|
||||
out[10] = (byte)(SBox[t0 >>> 8 & 0xff] ^ k >>> 8);
|
||||
out[11] = (byte)(SBox[t1 & 0xff] ^ k);
|
||||
out[12] = (byte)(SBox[t3 >>> 24] ^ (k = W[j + 3]) >>> 24);
|
||||
out[13] = (byte)(SBox[t0 >>> 16 & 0xff] ^ k >>> 16);
|
||||
out[14] = (byte)(SBox[t1 >>> 8 & 0xff] ^ k >>> 8);
|
||||
out[15] = (byte)(SBox[t2 & 0xff] ^ k);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the decryption of data.
|
||||
*/
|
||||
protected void decipherBlock() {
|
||||
|
||||
int j;
|
||||
int t0 = Util.getInt(holdData, 0) ^ W[j = Nr * 4];
|
||||
int t1 = Util.getInt(holdData, 4) ^ W[j + 1];
|
||||
int t2 = Util.getInt(holdData, 8) ^ W[j + 2];
|
||||
int t3 = Util.getInt(holdData, 12) ^ W[j + 3];
|
||||
|
||||
for (int i = 1; i < Nr; i++) {
|
||||
int v0, v1, v2;
|
||||
t0 = SB0[(v0 = t0) >>> 24] ^ SB1[t3 >>> 16 & 0xff] ^
|
||||
SB2[(v2 = t2) >>> 8 & 0xff] ^
|
||||
SB3[(v1 = t1) & 0xff] ^ W[j = j - 4];
|
||||
t1 = SB0[v1 >>> 24] ^ SB1[v0 >>> 16 & 0xff] ^
|
||||
SB2[t3 >>> 8 & 0xff] ^ SB3[v2 & 0xff] ^ W[j + 1];
|
||||
t2 = SB0[v2 >>> 24] ^ SB1[v1 >>> 16 & 0xff] ^
|
||||
SB2[v0 >>> 8 & 0xff] ^ SB3[t3 & 0xff] ^ W[j + 2];
|
||||
t3 = SB0[t3 >>> 24] ^ SB1[v2 >>> 16 & 0xff] ^
|
||||
SB2[v1 >>> 8 & 0xff] ^ SB3[v0 & 0xff] ^ W[j + 3];
|
||||
}
|
||||
|
||||
int k;
|
||||
byte out[];
|
||||
(out = state)[0] = (byte)(ISBox[t0 >>> 24] ^ (k = W[0])>>> 24);
|
||||
out[1] = (byte)(ISBox[t3 >>> 16 & 0xff] ^ k >>> 16);
|
||||
out[2] = (byte)(ISBox[t2 >>> 8 & 0xff] ^ k >>> 8);
|
||||
out[3] = (byte)(ISBox[t1 & 0xff] ^ k);
|
||||
out[4] = (byte)(ISBox[t1 >>> 24] ^ (k = W[1]) >>> 24);
|
||||
out[5] = (byte)(ISBox[t0 >>> 16 & 0xff] ^ k >>> 16);
|
||||
out[6] = (byte)(ISBox[t3 >>> 8 & 0xff] ^ k >>> 8);
|
||||
out[7] = (byte)(ISBox[t2 & 0xff] ^ k);
|
||||
out[8] = (byte)(ISBox[t2 >>> 24] ^ (k = W[2]) >>> 24);
|
||||
out[9] = (byte)(ISBox[t1 >>> 16 & 0xff] ^ k >>> 16);
|
||||
out[10] = (byte)(ISBox[t0 >>> 8 & 0xff] ^ k >>> 8);
|
||||
out[11] = (byte)(ISBox[t3 & 0xff] ^ k);
|
||||
out[12] = (byte)(ISBox[t3 >>> 24] ^ (k = W[3]) >>> 24);
|
||||
out[13] = (byte)(ISBox[t2 >>> 16 & 0xff] ^ k >>> 16);
|
||||
out[14] = (byte)(ISBox[t1 >>> 8 & 0xff] ^ k >>> 8);
|
||||
out[15] = (byte)(ISBox[t0 & 0xff] ^ k);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates KeySchedule.
|
||||
* @param data key data
|
||||
* @param mode cipher mode
|
||||
*/
|
||||
private void KeyExpansion(byte[] data, int mode) {
|
||||
|
||||
byte[] W = new byte[Nb * (Nr + 1) << 2];
|
||||
|
||||
int diff;
|
||||
System.arraycopy(data, 0, W, 0, (diff = Nk << 2));
|
||||
|
||||
int round = 1;
|
||||
for (int i = Nk; i < Nb * (Nr + 1); i++) {
|
||||
|
||||
int v = i << 2;
|
||||
|
||||
if (i % Nk == 0) {
|
||||
int u = v - 1;
|
||||
for (int j = 0; j < 4; j++, v++) {
|
||||
W[v] = (byte)((W[v - diff] ^
|
||||
SBox[W[u - ((6 - j) & 3)] & 0xff]));
|
||||
}
|
||||
W[i << 2] ^= Rcon[round++];
|
||||
} else
|
||||
if (Nk > 6 && i % Nk == 4) {
|
||||
for (int j = 0; j < 4; j++, v++) {
|
||||
W[v] = (byte) (W[v - diff] ^ SBox[W[v - 4] & 0xff]);
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < 4; j++, v++) {
|
||||
W[v] = (byte) (W[v - diff] ^ W[v - 4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int[] V = (this.W = new int[W.length >> 2]);
|
||||
for (int i = 0; i < V.length; i++) {
|
||||
V[i] = Util.getInt(W, i * 4);
|
||||
}
|
||||
|
||||
if (mode == Cipher.DECRYPT_MODE) {
|
||||
for (int i = 4; i < Nr * 4; i++) {
|
||||
V[i] = SB0[SBox[W[i * 4] & 0xff] & 0xff] ^
|
||||
SB1[SBox[W[i * 4 + 1] & 0xff] & 0xff] ^
|
||||
SB2[SBox[W[i * 4 + 2] & 0xff] & 0xff] ^
|
||||
SB3[SBox[W[i * 4 + 3] & 0xff] & 0xff];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package java.security;
|
||||
|
||||
import com.sun.satsa.crypto.RSAPublicKey;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
/**
|
||||
* Key factories are used to convert <I>key specifications</I>
|
||||
* (transparent representations of the underlying key material)
|
||||
* into <I>keys</I> (opaque cryptographic keys of type <code>Key</code>).
|
||||
*
|
||||
*
|
||||
*
|
||||
* @version 1.28, 05/07/02
|
||||
*
|
||||
* @see Key
|
||||
* @see PublicKey
|
||||
* @see java.security.spec.KeySpec
|
||||
* @see java.security.spec.X509EncodedKeySpec
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class KeyFactory {
|
||||
/**
|
||||
* Creates a KeyFactory object.
|
||||
*/
|
||||
KeyFactory() {}
|
||||
|
||||
/**
|
||||
* Generates a KeyFactory object that implements the specified
|
||||
* algorithm.
|
||||
*
|
||||
* @param algorithm the name of the requested key algorithm.
|
||||
* See Appendix A in the
|
||||
* Java Cryptography Architecture API Specification & Reference
|
||||
* for information about standard algorithm names.
|
||||
*
|
||||
* @return a <code>KeyFactory</code> object for the specified algorithm.
|
||||
*
|
||||
* @exception NoSuchAlgorithmException if the requested algorithm is
|
||||
* not available
|
||||
*/
|
||||
public static KeyFactory getInstance(String algorithm)
|
||||
throws NoSuchAlgorithmException {
|
||||
|
||||
if (algorithm.toUpperCase().equals("RSA")) {
|
||||
return new KeyFactory();
|
||||
}
|
||||
throw new NoSuchAlgorithmException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a public key object from the provided key specification
|
||||
* (key material).
|
||||
*
|
||||
* @param keySpec the specification (key material) of the public key.
|
||||
*
|
||||
* @return the public key.
|
||||
*
|
||||
* @exception InvalidKeySpecException if the given key specification
|
||||
* is inappropriate for this key factory to produce a public key.
|
||||
*/
|
||||
public final PublicKey generatePublic(KeySpec keySpec)
|
||||
throws InvalidKeySpecException {
|
||||
return new RSAPublicKey(keySpec);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package java.security.spec;
|
||||
|
||||
import com.sun.j2me.crypto.Util;
|
||||
|
||||
/**
|
||||
* This class represents a public key in encoded format.
|
||||
*
|
||||
*
|
||||
* @version 1.18, 01/23/03
|
||||
*
|
||||
* @see java.security.Key
|
||||
* @see java.security.KeyFactory
|
||||
* @see KeySpec
|
||||
* @see X509EncodedKeySpec
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public abstract class EncodedKeySpec implements KeySpec {
|
||||
/** The encoded key to use in the signature processing. */
|
||||
private byte[] encodedKey;
|
||||
|
||||
/**
|
||||
* Creates a new EncodedKeySpec with the given encoded key.
|
||||
*
|
||||
* @param encodedKey the encoded key.
|
||||
*/
|
||||
public EncodedKeySpec(byte[] encodedKey) {
|
||||
|
||||
this.encodedKey = Util.cloneArray(encodedKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encoded key.
|
||||
*
|
||||
* @return the encoded key.
|
||||
*/
|
||||
public byte[] getEncoded() {
|
||||
|
||||
return Util.cloneArray(encodedKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the encoding format associated with this
|
||||
* key specification.
|
||||
*
|
||||
* <p>If the opaque representation of a key
|
||||
* (see {@link java.security.Key Key}) can be generated
|
||||
* (see {@link java.security.KeyFactory KeyFactory})
|
||||
* from this key specification (or a subclass of it),
|
||||
* <code>getFormat</code> called
|
||||
* on the opaque key returns the same value as the
|
||||
* <code>getFormat</code> method
|
||||
* of this key specification.
|
||||
*
|
||||
* @return a string representation of the encoding format.
|
||||
*/
|
||||
public abstract String getFormat();
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package java.security.spec;
|
||||
|
||||
import java.security.*;
|
||||
/**
|
||||
* This is the exception for invalid key specifications.
|
||||
*
|
||||
*
|
||||
* @version 1.13, 01/23/03
|
||||
*
|
||||
* @see KeySpec
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class InvalidKeySpecException extends GeneralSecurityException {
|
||||
|
||||
/**
|
||||
* Constructs an InvalidKeySpecException with no detail message. A
|
||||
* detail message is a String that describes this particular
|
||||
* exception.
|
||||
*/
|
||||
public InvalidKeySpecException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an InvalidKeySpecException with the specified detail
|
||||
* message. A detail message is a String that describes this
|
||||
* particular exception.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public InvalidKeySpecException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License version 2 for more details (a copy is
|
||||
* included at /legal/license.txt).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this work; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
|
||||
* Clara, CA 95054 or visit www.sun.com if you need additional
|
||||
* information or have any questions.
|
||||
*/
|
||||
|
||||
package java.security.spec;
|
||||
|
||||
/**
|
||||
* This class represents the ASN.1 encoding of a public key,
|
||||
* encoded according to the ASN.1 type <code>SubjectPublicKeyInfo</code>.
|
||||
* The <code>SubjectPublicKeyInfo</code> syntax is defined in the X.509
|
||||
* standard as follows:
|
||||
*
|
||||
* <pre>
|
||||
* SubjectPublicKeyInfo ::= SEQUENCE {
|
||||
* algorithm AlgorithmIdentifier,
|
||||
* subjectPublicKey BIT STRING }
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @version 1.17, 01/23/03
|
||||
*
|
||||
* @see java.security.Key
|
||||
* @see java.security.KeyFactory
|
||||
* @see KeySpec
|
||||
* @see EncodedKeySpec
|
||||
*
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
public class X509EncodedKeySpec extends EncodedKeySpec {
|
||||
|
||||
/**
|
||||
* Creates a new X509EncodedKeySpec with the given encoded key.
|
||||
*
|
||||
* @param encodedKey the key, which is assumed to be
|
||||
* encoded according to the X.509 standard.
|
||||
*/
|
||||
public X509EncodedKeySpec(byte[] encodedKey) {
|
||||
super(encodedKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key bytes, encoded according to the X.509 standard.
|
||||
*
|
||||
* @return the X.509 encoding of the key.
|
||||
*/
|
||||
public byte[] getEncoded() {
|
||||
return super.getEncoded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the encoding format associated with this
|
||||
* key specification.
|
||||
*
|
||||
* @return the string <code>"X.509"</code>.
|
||||
*/
|
||||
public final String getFormat() {
|
||||
return "X.509";
|
||||
}
|
||||
}
|
57
signature.js
57
signature.js
|
@ -26,56 +26,16 @@ var Signature = (function() {
|
|||
}
|
||||
};
|
||||
|
||||
function _parse(part) {
|
||||
var res = [];
|
||||
var slots = 0;
|
||||
if (part != '') {
|
||||
var isArray = false;
|
||||
var pos = 0;
|
||||
while (pos < part.length) {
|
||||
switch(part[pos]) {
|
||||
case TYPE.long:
|
||||
case TYPE.double:
|
||||
++slots;
|
||||
// fall through
|
||||
case TYPE.boolean:
|
||||
case TYPE.byte:
|
||||
case TYPE.char:
|
||||
case TYPE.float:
|
||||
case TYPE.int:
|
||||
case TYPE.short:
|
||||
res.push({ type: TYPE.toString(part[pos]), isArray: isArray });
|
||||
isArray = false;
|
||||
break;
|
||||
case TYPE.object:
|
||||
var className = '';
|
||||
while (part[++pos] !== ';') {
|
||||
className += part[pos];
|
||||
}
|
||||
res.push({ type: "object", isArray: isArray, className: className });
|
||||
isArray = false;
|
||||
break;
|
||||
case TYPE.array:
|
||||
isArray = true;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
slots += res.length;
|
||||
res.slots = slots;
|
||||
return res;
|
||||
}
|
||||
|
||||
function getINSlots(signature) {
|
||||
var slots = 0;
|
||||
|
||||
var pos = 0;
|
||||
var isArray = false;
|
||||
while (pos < signature.length) {
|
||||
switch (signature[pos]) {
|
||||
case TYPE.long:
|
||||
case TYPE.double:
|
||||
slots += 2;
|
||||
slots += isArray ? 1 : 2;
|
||||
break;
|
||||
|
||||
case TYPE.boolean:
|
||||
|
@ -94,8 +54,13 @@ var Signature = (function() {
|
|||
|
||||
case ')':
|
||||
return slots;
|
||||
case TYPE.array:
|
||||
isArray = true;
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
isArray = false;
|
||||
pos++;
|
||||
}
|
||||
|
||||
|
@ -103,14 +68,6 @@ var Signature = (function() {
|
|||
}
|
||||
|
||||
return {
|
||||
parse: function(s) {
|
||||
var IN = s.split(')')[0].substr(1);
|
||||
var OUT = s.split(')')[1];
|
||||
return {
|
||||
IN: _parse(IN),
|
||||
OUT: _parse(OUT)
|
||||
};
|
||||
},
|
||||
getINSlots: getINSlots,
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -39,7 +39,7 @@ casper.test.begin("unit tests", 5 + gfxTests.length, function(test) {
|
|||
.withFrame(0, function() {
|
||||
casper.waitForText("DONE", function() {
|
||||
var content = this.getPageContent();
|
||||
if (content.contains("DONE: 70911 pass, 0 fail, 175 known fail, 0 unknown pass")) {
|
||||
if (content.contains("DONE: 70921 pass, 0 fail, 175 known fail, 0 unknown pass")) {
|
||||
test.pass('main unit tests');
|
||||
} else {
|
||||
this.debugPage();
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package java.lang;
|
||||
|
||||
import gnu.testlet.Testlet;
|
||||
import gnu.testlet.TestHarness;
|
||||
|
||||
public class TestArrayPrameter implements Testlet {
|
||||
private boolean testBooleanArray(boolean[] array) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean testByteArray(byte[] array) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean testCharArray(char[] array) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean testDoubleArray(double[] array) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean testFloatArray(float[] array) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean testIntArray(int[] array) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean testLongArray(long[] array) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean testObjectArray(Object[] array) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean testShortArray(short[] array) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean testMultiDArray(Object[][] array) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void test(TestHarness th) {
|
||||
th.check(testBooleanArray(null));
|
||||
th.check(testByteArray(null));
|
||||
th.check(testCharArray(null));
|
||||
th.check(testDoubleArray(null));
|
||||
th.check(testFloatArray(null));
|
||||
th.check(testIntArray(null));
|
||||
th.check(testLongArray(null));
|
||||
th.check(testObjectArray(null));
|
||||
th.check(testShortArray(null));
|
||||
th.check(testMultiDArray(null));
|
||||
}
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче