java 从 Linux 64 位访问 javax.smartcardio

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12376257/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 08:38:14  来源:igfitidea点击:

Accessing javax.smartcardio from Linux 64 bits

javasmartcardpcsc

提问by Gilberto Torrezan

I'm trying to load the smartcard terminals using the javax.smartcardio API with the following code:

我正在尝试使用带有以下代码的 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;
}

... and I always get the following exception:

...我总是得到以下异常:

java.lang.IllegalStateException: no terminals
at javax.smartcardio.TerminalFactory$NoneCardTerminals.waitForChange(TerminalFactory.java:145)

On Windows Vista/7 everything works fine, but I can't get it to work on Linux. I'm using Ubuntu 12.04 64 bits.

在 Windows Vista/7 上一切正常,但我无法让它在 Linux 上工作。我正在使用 Ubuntu 12.04 64 位。

I installed the pcscd service using the following command:

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

sudo apt-get install libccid pcscd libpcsclite-dev libpcsclite1
sudo service pcscd start

And the pcsc_scan command prints this:

并且 pcsc_scan 命令打印:

PC/SC device scanner
V 1.4.18 (c) 2001-2011, Ludovic Rousseau <[email protected]>
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>
  ...

So everything looks ok, but the smartcardio just doesn't work. I'm trying with both Oracle and OpenJDK 1.7.0_05, 32 and 64 bits.

所以一切看起来都不错,但是 smartcardio 就是不工作。我正在尝试使用 Oracle 和 OpenJDK 1.7.0_05、32 和 64 位。

The code runs ok with OpenJDK (but not with Oracle JDK, don't know really why) on a Ubuntu 32 bits environment. So I think it is a problem with the 64 bits bridge from Java to the PC/SC library.

该代码在 Ubuntu 32 位环境中使用 OpenJDK(但不适用于 Oracle JDK,不知道为什么)运行正常。所以我认为这是从 Java 到 PC/SC 库的 64 位桥接的问题。

Any ideas?

有任何想法吗?

Thanks.

谢谢。

回答by Jostein Stuhaug

I think I found a workaround for this as I just had a similar problem. In a bugreport from ubuntuit says that the javax.smartcardio library searches for the PC/SC library in the wrong directory.

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

By specifying the path to the PC/SC library on my machine, like the bugreport mentions, I got it working.

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

The paths in the bugreport are wrong for me, I'm on 64 bit fedora, where the pc/sc library are installed at /usr/lib64/libpcsclite.so.1

错误报告中的路径对我来说是错误的,我使用的是 64 位 Fedora,其中 pc/sc 库安装在 /usr/lib64/libpcsclite.so.1

So the workaround for me is to specify the library path to java like this:

所以我的解决方法是像这样指定 java 的库路径:

java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1

Depending on your Linux distribution, the location of libpcsclite.so.1actually might differ, it could also be at /lib/x86_64-linux-gnu/libpcsclite.so.1(i.e. Kubuntu 15.04). In that case, call it like this:

根据您的 Linux 发行版,libpcsclite.so.1实际位置可能有所不同,也可能在/lib/x86_64-linux-gnu/libpcsclite.so.1(即 Kubuntu 15.04)。在这种情况下,像这样调用它:

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

回答by Ian Agung

i'm using raspberry with debian arm version

我正在使用带有 debian arm 版本的 raspberry

find the location of libpcsclite first with:

首先找到 libpcsclite 的位置:

$ ldd -r /usr/bin/pcsc_scan

and then use the libpcsclite location with:

然后使用 libpcsclite 位置:

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

回答by Brett Cherrington

For anyone else struggling with this on Ubuntu 14 with a 64 bit machine. I found the .so file is actually located in the following directory

对于使用 64 位机器在 Ubuntu 14 上为此苦苦挣扎的其他人。我发现 .so 文件实际上位于以下目录中

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

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

So running my app with the setting as below worked for me

因此,使用以下设置运行我的应用程序对我有用

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

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

回答by AshanPerera

You need to give the path to the libpcsclite.so.1 when calling your program as follows

调用程序时需要提供 libpcsclite.so.1 的路径,如下所示

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

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

If you don't know the path to the library, use the following command

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

find /usr/lib -name libpcsclite.so.1

This usually shows you the path on your machine. I used it on both Ubuntu 10 (32bit) and Ubuntu 15(32bit and 64bit)

这通常会显示您机器上的路径。我在 Ubuntu 10(32 位)和 Ubuntu 15(32 位和 64 位)上都使用过它

If you're lazy like me, what you can do is include this part of code in your program before you use the javax.smartcardio library

如果你像我一样懒惰,你可以做的就是在使用 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();
        }

Now you can run your code from as usual without including the path to libpcsclite.so.1

现在您可以照常运行您的代码,而无需包含 libpcsclite.so.1 的路径

回答by JWnxp

Addition to the solution with supplying the path as a parameter like this:

除了提供路径作为参数的解决方案,如下所示:

java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1

If you don't want to supply this every time you call the JVM, set it in the environment variables _JAVA_OPTIONS and/or JAVA_OPTS:

如果您不想在每次调用 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"

Since this is a workaround for bug that affects the entire system, it makes sense IMHO to apply this workaround systemwide as well.

由于这是影响整个系统的错误的解决方法,恕我直言,在系统范围内应用此解决方法也是有意义的。

JAVA_OPTS has local scope and has to be evaluated by scripts running your code; _JAVA_OPTIONS is supposed to be evaluated automatically by the JRE.

JAVA_OPTS 具有局部作用域,必须由运行代码的脚本进行评估;_JAVA_OPTIONS 应该由 JRE 自动评估。

回答by vlp

Yet another approach (my favorite) is to make some symbolic links.

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

It has the advantage that it works system-wide (no jvm arguments, no environment variables).

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

For my (beloved) debian jessie amd64:

对于我(心爱的)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

Note: This will probably require superuseraccess.

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

回答by R. Cozendey

Complementing @AshanPerera answer, as sometimes searching each time can be slow, you can search it at the first time, and them store the location in a file, and read it from then on:

补充@AshanPerera 的答案,因为有时每次搜索可能很慢,您可以在第一次搜索它,然后将位置存储在一个文件中,然后从那时起读取它:

        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();
    }