从Linux 64位访问javax.smartcardio

从Linux 64位访问javax.smartcardio,java,smartcard,pcsc,Java,Smartcard,Pcsc,我尝试使用javax.smartcardio API加载智能卡终端,代码如下: public CardTerminal getReadyCardTerminal() throws CardException { TerminalFactory factory = TerminalFactory.getDefault(); CardTerminals terminals = factory.terminals(); List<CardTerminal> lis

我尝试使用javax.smartcardio API加载智能卡终端,代码如下:

public CardTerminal getReadyCardTerminal() throws CardException {

    TerminalFactory factory = TerminalFactory.getDefault();
    CardTerminals terminals = factory.terminals();
    List<CardTerminal> list = terminals.list(State.CARD_PRESENT);

    while (list.isEmpty()) {
        terminals.waitForChange(1000);
        list = terminals.list(State.CARD_PRESENT);
    }
    CardTerminal cardTerminal = list.get(0);
    return cardTerminal;
}
在WindowsVista/7上,一切正常,但我无法让它在Linux上运行。我使用的是Ubuntu 12.04 64位

我使用以下命令安装了pcscd服务:

sudo apt-get install libccid pcscd libpcsclite-dev libpcsclite1
sudo service pcscd start
pcsc_scan命令将打印以下内容:

PC/SC device scanner
V 1.4.18 (c) 2001-2011, Ludovic Rousseau <ludovic.rousseau@free.fr>
Compiled with PC/SC lite version: 1.7.4
Using reader plug'n play mechanism
Scanning present readers...
0: OMNIKEY CardMan 3x21 00 00

Tue Sep 11 15:44:49 2012
Reader 0: OMNIKEY CardMan 3x21 00 00
  Card state: Card inserted, 
  ATR: <some hexa codes>
  ...
PC/SC设备扫描仪
V 1.4.18(c)2001-2011,卢多维奇·卢梭
使用PC/SC lite版本编译:1.7.4
使用读卡器即插即用机制
扫描当前读者。。。
0:OMNIKEY CardMan 3x21 00
2012年9月11日星期二15:44:49
读卡器0:OMNIKEY CardMan 3x21 00
卡片状态:已插入卡片,
自动标签阅读器:
...
所以看起来一切正常,但smartcardio就是不起作用。我正在尝试使用Oracle和OpenJDK 1.7.0_05、32和64位

代码在Ubuntu 32位环境下使用OpenJDK运行正常(但不使用Oracle JDK,不知道为什么)。因此,我认为从Java到PC/SC库的64位网桥存在问题

有什么想法吗


谢谢。

我想我找到了解决方法,因为我刚刚遇到了类似的问题。在一份声明中,它说javax.smartcardio库在错误的目录中搜索PC/SC库

通过在我的机器上指定PC/SC库的路径,就像bugreport提到的那样,我让它工作了

bugreport中的路径对我来说是错误的,我在64位fedora上,pc/sc库安装在/usr/lib64/libpcsclite.so.1

因此,我的解决方法是指定java的库路径,如下所示:

java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1
java -Dsun.security.smartcardio.library=/lib/x86_64-linux-gnu/libpcsclite.so.1
java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1
根据您的Linux发行版,
libpcsclite.so.1
的位置实际上可能不同,它也可能位于
/lib/x86\u 64-Linux-gnu/libpcsclite.so.1
(即Kubuntu 15.04)。 在这种情况下,可以这样称呼:

java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1
java -Dsun.security.smartcardio.library=/lib/x86_64-linux-gnu/libpcsclite.so.1
java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1

我用的是树莓和debian arm版本

首先使用以下命令查找libpcsclite的位置:

$ ldd -r /usr/bin/pcsc_scan
然后将libpcsclite位置用于:

java -Dsun.security.smartcardio.library=/usr/lib/arm-linux-gnueabihf/libpcsclite.so.1

对于其他在Ubuntu 14上使用64位机器进行此操作的用户。我发现.so文件实际上位于以下目录中

/usr/lib/x86_64-linux-gnu/libpcsclite.so

所以用下面的设置运行我的应用程序对我来说很有效


-Dsun.security.smartcardio.library=/usr/lib/x86_64-linux-gnu/libpcsclite.so

将路径作为如下参数添加到解决方案中:

java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1
java -Dsun.security.smartcardio.library=/lib/x86_64-linux-gnu/libpcsclite.so.1
java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1
如果不想在每次调用JVM时都提供此选项,请在环境变量_JAVA_OPTIONS和/或JAVA_OPTS中设置它:

export _JAVA_OPTIONS="-Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1"
export JAVA_OPTS="-Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1"
因为这是一个解决影响整个系统的bug的方法,所以在系统范围内应用这个方法也是有意义的

JAVA_OPTS具有本地作用域,必须通过运行代码的脚本进行评估_JAVA_选项应该由JRE自动评估。

另一种方法(我最喜欢)是创建一些符号链接

它的优点是在系统范围内工作(没有jvm参数,没有环境变量)

送给我(亲爱的)debian jessie amd64:

ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so libpcsclite.so
ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so.1 libpcsclite.so.1
ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so.1.0.0 libpcsclite.so.1.0.0

注意:这可能需要超级用户访问。

在按如下方式调用程序时,需要提供libpcsclite.so.1的路径

java-Dsun.security.smartcardio.library=/path/to/libpcsclite.so.1

如果不知道库的路径,请使用以下命令

find /usr/lib -name libpcsclite.so.1
这通常会显示机器上的路径。我在Ubuntu10(32位)和Ubuntu15(32位和64位)上都使用了它

如果您像我一样懒惰,那么您可以在使用javax.smartcardio库之前将这部分代码包含在程序中

      try {
            String comm[] = { "find", "/usr", "/lib", "-name",
                    "libpcsclite.so.1" };
            Process p = Runtime.getRuntime().exec(comm);

            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(p.getInputStream()));

            while ((line = reader.readLine()) != null && !line.equals("")) {
                if (line.contains("libpcsclite.so.1")) {
                System.setProperty("sun.security.smartcardio.library",line);
                    break;
                }

            }
            p.waitFor();

        } catch (Exception e) {

            e.printStackTrace();
        }

现在,您可以像往常一样从运行代码,而不包括libpcsclite.so.1的路径,这是对@AshanPerera answer的补充,因为有时每次搜索都会很慢,您可以在第一次搜索它,然后他们将位置存储在文件中,然后从那时开始读取:

        try {

        String filename = "libpcsclite.location"; 
        File propertyFile = new File(filename);
        if(propertyFile.createNewFile()) 
        {   
            String commandWithArguments[] = { "find", "/usr", "/lib", "-name","libpcsclite.so.1" };
            Process searchProcess = Runtime.getRuntime().exec(commandWithArguments);
            BufferedReader searchReader = new BufferedReader(new InputStreamReader(searchProcess.getInputStream()));
            String propertyValue;
            while ( (propertyValue = searchReader.readLine()) != null && !propertyValue.equals("")) 
            {
                if (propertyValue.contains("libpcsclite.so.1")) {
                    BufferedWriter propertyWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(propertyFile)));
                    propertyWriter.write(propertyValue);
                    propertyWriter.close();
                    System.setProperty("sun.security.smartcardio.library",propertyValue);
                    break;
                }
            }
            searchProcess.waitFor();
        }
        else 
        {  
            BufferedReader propertyReader = new BufferedReader(new InputStreamReader(new FileInputStream(propertyFile)));                 
            String propertyValue = propertyReader.readLine(); 
            System.setProperty("sun.security.smartcardio.library",propertyValue);       
        }
    } catch (Exception e) {

        e.printStackTrace();
    }

顺便说一下,pcsc_scan命令来自pcsc工具包。问得好。我确实在我的Ubuntu盒上自己解决了这个问题,但很好它现在被记录在某个可以找到的地方。谢谢你!这就解决了问题。在Ubuntu上,路径是/usr/lib/libpcsclite.so.1Newbie这里,为了清楚起见,我可以在终端或何处运行:“java-Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1”?是的,当您使用java命令启动程序时。类似于“java-Dsun.secu…-jaryourprogram.jar”。它还可以与java 1_8_25一起用于debian wheezy(在本例中为:-Dsun.security.smartcardio.library=/usr/lib/libpcsclite.so.1)Life saver。谢谢。我已经设法让读卡器工作了,有办法解决这个问题吗?现在,每次我尝试运行程序时,我都需要java-Dsun.security.smartcardio.library=/usr/lib/arm-linux-gnueabihf/libpcsclite.so.1 Test.jar ir才能正常工作。如果我执行java-jar Test.jar,它会给出找不到的错误main class。我到libpcsclite.so的路径是-Dsun.security.smartcardio.library=/usr/libpcsclite.so.1,这是有效,但仍无法获取任何终端列表。你能给我一些实施的细节吗?嗨,我能知道这是什么吗?这是一个未定义的对象。line=reader.readLine()我已经有一段时间没有使用它了,但我认为您可以在reader之前将
line
定义为空字符串。readLine()被称为dok:-)谢谢