/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2010 Oracle and/or its affiliates. All rights reserved. * * Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. * * Contributor(s): * * Portions Copyrighted 2009 Sun Microsystems, Inc. */ package org.netbeans.modules.keyring.win32; import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.Structure; import com.sun.jna.WString; import com.sun.jna.win32.StdCallLibrary; import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import java.util.logging.Level; import java.util.logging.Logger; import org.netbeans.modules.keyring.utils.Utils; import org.netbeans.modules.keyring.spi.EncryptionProvider; /** * Data protection utility for Microsoft Windows. * XXX org.tmatesoft.svn.core.internal.util.jna.SVNWinCrypt is a possibly more robust implementation * (though it seems to set CRYPTPROTECT_UI_FORBIDDEN which we do not necessarily want). */ public class Win32Protect implements EncryptionProvider { private static final Logger LOG = Logger.getLogger(Win32Protect.class.getName()); public @Override boolean enabled() { // asssume, we have windows os try { if (CryptLib.INSTANCE == null) { LOG.fine("loadLibrary -> null"); return false; } return true; } catch (Throwable t) { LOG.log(Level.FINE, null, t); return false; } } public @Override String id() { return "win32"; // NOI18N } public @Override byte[] encrypt(char[] cleartext) throws Exception { byte[] cleartextB = Utils.chars2Bytes(cleartext); CryptIntegerBlob input = new CryptIntegerBlob(); input.store(cleartextB); Arrays.fill(cleartextB, (byte) 0); CryptIntegerBlob output = new CryptIntegerBlob(); if (!CryptLib.INSTANCE.CryptProtectData(input, null, null, null, null, 0, output)) { throw new Exception("CryptProtectData failed: " + Native.getLastError()); } input.zero(); return output.load(); } public @Override char[] decrypt(byte[] ciphertext) throws Exception { CryptIntegerBlob input = new CryptIntegerBlob(); input.store(ciphertext); CryptIntegerBlob output = new CryptIntegerBlob(); if (!CryptLib.INSTANCE.CryptUnprotectData(input, null, null, null, null, 0, output)) { throw new Exception("CryptUnprotectData failed: " + Native.getLastError()); } byte[] result = output.load(); // XXX gives CCE because not a Memory: output.zero(); char[] cleartext = Utils.bytes2Chars(result); Arrays.fill(result, (byte) 0); return cleartext; } public @Override boolean decryptionFailed() { return false; // not much to do about it } public @Override void encryptionChangingCallback(Callable<Void> callback) {} public @Override void encryptionChanged() { assert false; } public @Override void freshKeyring(boolean fresh) {} public interface CryptLib extends StdCallLibrary { CryptLib INSTANCE = (CryptLib) Native.loadLibrary("Crypt32", CryptLib.class); // NOI18N /** @see <a href="http://msdn.microsoft.com/en-us/library/aa380261(VS.85,printer).aspx">Reference</a> */ boolean CryptProtectData( CryptIntegerBlob pDataIn, WString szDataDescr, CryptIntegerBlob pOptionalEntropy, Pointer pvReserved, Pointer pPromptStruct, int dwFlags, CryptIntegerBlob pDataOut )/* throws LastErrorException*/; /** @see <a href="http://msdn.microsoft.com/en-us/library/aa380882(VS.85,printer).aspx">Reference</a> */ boolean CryptUnprotectData( CryptIntegerBlob pDataIn, WString[] ppszDataDescr, CryptIntegerBlob pOptionalEntropy, Pointer pvReserved, Pointer pPromptStruct, int dwFlags, CryptIntegerBlob pDataOut )/* throws LastErrorException*/; } public static class CryptIntegerBlob extends Structure { public int cbData; public /*byte[]*/Pointer pbData; byte[] load() { return pbData.getByteArray(0, cbData); // XXX how to free pbData? [Kernel32]LocalFree? } void store(byte[] data) { cbData = data.length; pbData = new Memory(data.length); pbData.write(0, data, 0, cbData); } void zero() { ((Memory) pbData).clear(); } @Override protected List<String> getFieldOrder() { return Arrays.asList( new String[] { "cbData", "pbData", } ); } } }